Swift - GLKit View CIFilter Image - swift2

I am trying to use a GLIKit View in order to modify an Image. The class I have so far is working well all the CIFilters except for the CILineOverlay it renders a black view. If I use any other effect it works well.
Why is the CILineOverlay not showing?
class ImageView: GLKView {
let clampFilter = CIFilter(name: "CIAffineClamp")!
let blurFilter = CIFilter(name: "CILineOverlay")!
let ciContext:CIContext
override init(frame: CGRect) {
let glContext = EAGLContext(API: .OpenGLES2)
ciContext = CIContext(
EAGLContext: glContext,
options: [
kCIContextWorkingColorSpace: NSNull()
]
)
super.init(frame: frame, context: glContext)
enableSetNeedsDisplay = true
}
required init(coder aDecoder: NSCoder) {
let glContext = EAGLContext(API: .OpenGLES2)
ciContext = CIContext(
EAGLContext: glContext,
options: [
kCIContextWorkingColorSpace: NSNull()
]
)
super.init(coder: aDecoder)!
context = glContext
enableSetNeedsDisplay = true
}
#IBInspectable var inputImage: UIImage? {
didSet {
inputCIImage = inputImage.map { CIImage(image: $0)! }
}
}
#IBInspectable var blurRadius: Float = 0 {
didSet {
//blurFilter.setValue(blurRadius, forKey: "inputIntensity")
setNeedsDisplay()
}
}
var inputCIImage: CIImage? {
didSet { setNeedsDisplay() }
}
override func drawRect(rect: CGRect) {
if let inputCIImage = inputCIImage {
clampFilter.setValue(inputCIImage, forKey: kCIInputImageKey)
blurFilter.setValue(clampFilter.outputImage!, forKey: kCIInputImageKey)
let rect = CGRect(x: 0, y: 0, width: drawableWidth, height: drawableHeight)
ciContext.drawImage(blurFilter.outputImage!, inRect: rect, fromRect: inputCIImage.extent)
}
}
}

The Apple docs states "The portions of the image that are not outlined are transparent." - this means you are drawing black lines over a black background. You can simply composite the output from the filter over a white background to make the lines appear:
let background = CIImage(color: CIColor(color: UIColor.whiteColor()))
.imageByCroppingToRect(inputCIImage.extent)
let finalImage = filter.outputImage!
.imageByCompositingOverImage(background)

Related

Xcode: How do I reset the state of all Buttons from the main view controller using a class

I have a class for my buttons that changes the colour when pressed, alternating between on and off.
class KSPickButton: UIButton {
var isOn = true
override init(frame: CGRect) {
super.init(frame: frame)
initButton()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
initButton()
}
func initButton() {
layer.borderWidth = 2.0
layer.borderColor = Colors.shanklinGreen.cgColor
layer.cornerRadius = frame.size.height/2
backgroundColor = .clear
setTitleColor(.white, for: .normal)
addTarget(self, action: #selector(KSPickButton.buttonPressed), for: .touchUpInside)
}
#objc func buttonPressed() {
activateButton(bool: !isOn)
}
func activateButton(bool: Bool) {
isOn = bool
let color = bool ? .clear : Colors.shanklinGreen
//let title = bool ? "" : ""
let titleColor = bool ? .white: Colors.shanklinBlack
//setTitle(title, for: .normal)
setTitleColor(titleColor, for: .normal)
backgroundColor = color
}
}
This works perfectly. I have 20 buttons on my main view controller and they flip between on and off as expected... Then maybe after pressing 6, I want to reset them all to off. I have a reset button on my main view controller, but I cannot work out how I can reset them all?
I can make them all look reset but the bool remains as was...
How do I call this class for all buttons and reset them correctly?
Introduced an observer with 'isOn' variable. You can try using following code snippet in 'KSPickButton' class. After that you need to take all subviews from view controllers (where buttons are placed) and set 'isOn' to 'false' for all of them.
class KSPickButton: UIButton {
public var isOn:Bool = true {
didSet {
handleButtonStateChange()
}
}
override init(frame: CGRect) {
super.init(frame: frame)
initButton()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
initButton()
}
func initButton() {
layer.borderWidth = 2.0
layer.borderColor = Colors.shanklinGreen.cgColor
layer.cornerRadius = frame.size.height/2
backgroundColor = .clear
setTitleColor(.white, for: .normal)
addTarget(self, action: #selector(KSPickButton.buttonPressed), for: .touchUpInside)
}
#objc func buttonPressed() {
isOn = !isOn
}
func handleButtonStateChange() {
let color = isOn ? .clear : Colors.shanklinGreen
let titleColor = isOn ? .white: Colors.shanklinBlack
setTitleColor(titleColor, for: .normal)
backgroundColor = color
}
}
Here is code snippet you need to implement in your view controller as explained above.
class MyVC: UIViewController {
------
------
for subview in view.subviews where subview.isKind(of: KSPickButton.self)&&(subview as? KSPickButton)?.isOn == true {
(subview as? KSPickButton)?.isOn = false
}
-----
-----
}

NSSplitviewController programmatically

I have a NSSplitViewController with 2 view controllers as splitViewItems.
This works fine.
Now I would like to set an own SplitViewController Class for my Splitviewcontroller in the storyboard. I give it my own class start the app. But now I only see an empty window.
Have I set my splitviewcontroller now programmatically, if I set my own splitviewcontroller class?
If yes, which code I have to use to show the two view controllers in my splitview controller again?
UPDATE
import Cocoa
class SplitViewController: NSSplitViewController {
override func viewDidLoad() {
print("Test")
}
}
Here is an Xcode 9 Playground (Swift 4) which shows how to setup NSSplitViewController from code.
import Cocoa
import PlaygroundSupport
class ViewController: NSViewController {
private let backgroundColor: NSColor
init(backgroundColor: NSColor) {
self.backgroundColor = backgroundColor
super.init(nibName: nil, bundle: nil)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func loadView() {
view = NSView()
view.wantsLayer = true
view.layer?.backgroundColor = backgroundColor.cgColor
}
}
class MainSplitViewController: NSSplitViewController {
private let splitViewResorationIdentifier = "com.company.restorationId:mainSplitViewController"
lazy var vcA = ViewController(backgroundColor: .red)
lazy var vcB = ViewController(backgroundColor: .green)
lazy var vcC = ViewController(backgroundColor: .blue)
override init(nibName nibNameOrNil: NSNib.Name?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
setupUI()
setupLayout()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
}
extension MainSplitViewController {
private func setupUI() {
view.wantsLayer = true
splitView.dividerStyle = .paneSplitter
splitView.autosaveName = NSSplitView.AutosaveName(rawValue: splitViewResorationIdentifier)
splitView.identifier = NSUserInterfaceItemIdentifier(rawValue: splitViewResorationIdentifier)
}
private func setupLayout() {
minimumThicknessForInlineSidebars = 180
let itemA = NSSplitViewItem(sidebarWithViewController: vcA)
itemA.minimumThickness = 80
addSplitViewItem(itemA)
let itemB = NSSplitViewItem(contentListWithViewController: vcB)
itemB.minimumThickness = 100
addSplitViewItem(itemB)
let itemC = NSSplitViewItem(viewController: vcC)
itemC.minimumThickness = 80
addSplitViewItem(itemC)
}
}
let vc = MainSplitViewController()
vc.view.frame = CGRect(x: 0, y: 0, width: 400, height: 300)
PlaygroundPage.current.liveView = vc
UPDATE:
Version similar to one above but targeted to macOS 10.10.
import Cocoa
import PlaygroundSupport
class ViewController: NSViewController {
private let backgroundColor: NSColor
init(backgroundColor: NSColor) {
self.backgroundColor = backgroundColor
super.init(nibName: nil, bundle: nil)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func loadView() {
view = NSView()
view.wantsLayer = true
view.layer?.backgroundColor = backgroundColor.cgColor
}
}
class MainSplitViewController: NSSplitViewController {
private let splitViewResorationIdentifier = "com.company.restorationId:mainSplitViewController"
lazy var vcA = ViewController(backgroundColor: .red)
lazy var vcB = ViewController(backgroundColor: .green)
lazy var vcC = ViewController(backgroundColor: .blue)
override init(nibName nibNameOrNil: NSNib.Name?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
setupUI()
setupLayout()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
}
extension MainSplitViewController {
private func setupUI() {
view.wantsLayer = true
splitView.dividerStyle = .paneSplitter
splitView.autosaveName = NSSplitView.AutosaveName(rawValue: splitViewResorationIdentifier)
splitView.identifier = NSUserInterfaceItemIdentifier(rawValue: splitViewResorationIdentifier)
vcA.view.widthAnchor.constraint(greaterThanOrEqualToConstant: 80).isActive = true
vcB.view.widthAnchor.constraint(greaterThanOrEqualToConstant: 100).isActive = true
vcC.view.widthAnchor.constraint(greaterThanOrEqualToConstant: 80).isActive = true
}
private func setupLayout() {
let sidebarItem = NSSplitViewItem(viewController: vcA)
sidebarItem.canCollapse = true
sidebarItem.holdingPriority = NSLayoutConstraint.Priority(NSLayoutConstraint.Priority.defaultLow.rawValue + 1)
addSplitViewItem(sidebarItem)
let xibItem = NSSplitViewItem(viewController: vcB)
addSplitViewItem(xibItem)
let codeItem = NSSplitViewItem(viewController: vcC)
addSplitViewItem(codeItem)
}
}
let vc = MainSplitViewController()
vc.view.frame = CGRect(x: 0, y: 0, width: 400, height: 300)
PlaygroundPage.current.liveView = vc

NSCollectionView single selection is not working, but multiple selection is fine

As title described,
my NSCollectionView is not working when single selection.
MyNSCollectionView is rendered correcttly,
below code shows how I initialize my NSCollectionView:
self.leftBar.dataSource = self
self.leftBar.delegate = self
self.leftBar.isSelectable = true
self.leftBar.allowsEmptySelection = true
let layout = NSCollectionViewFlowLayout()
layout.scrollDirection = .horizontal
layout.itemSize = NSSize(width: 200 , height: 50)
leftBar.collectionViewLayout = layout
self.contentView.addSubview(leftBar)
leftBar <- [
Top(),
Left(),
Bottom(),
Width(200)
]
Custom NSCollectionViewItem
class LeftBarCell: NSCollectionViewItem {
var leftBarView : LeftBarView?
override func loadView() {
leftBarView = LeftBarView(frame: NSZeroRect)
view = leftBarView!
}
func setup(title : String){
leftBarView?.titleTextView.string = title
}
}
In LeftBarView
class LeftBarView: NSView {
lazy var titleTextView : NSTextView = {
let titleTextView = NSTextView()
titleTextView.isEditable = false
titleTextView.isSelectable = false
titleTextView.font = NSFont(name: "Helvetica", size: 20)
return titleTextView
}()
override init(frame frameRect: NSRect) {
super.init(frame: frameRect)
self.setupViews()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
func setupViews(){
self.addSubview(titleTextView)
self.wantsLayer = true
self.layer?.backgroundColor = NSColor.lightGray.cgColor
titleTextView <- Edges()
}
}
I tried to play around with
self.leftBar.isSelectable = true
leftBar.allowsMultipleSelection = true
and multiple selection is working.
The didSelectItemsAt from NSCollectionViewDelegate is triggered
But then when I try with this
self.leftBar.isSelectable = true
or
self.leftBar.isSelectable = true
self.leftBar.allowsEmptySelection = true
It is not working when I click on the collectionviewitem,
The didSelectItemsAt from NSCollectionViewDelegate is not triggered.
Any thoughts would be appreciated, thanks!
Solved. This is because the textview covers the cell, u might need to disable the textview to become passive.
extension NSTextView {
open override func hitTest(_ point: NSPoint) -> NSView? {
return nil
}
}

UISwitch set on/off Image

I want to set my Switch like this:
But I try in ios9 , it does not work.
I saw in apple UISwitch Class Reference.
It says that :
Discussion
In iOS 7, this property has no effect.
How about iOS 9? Any one success?
My Code:
switch1 = UISwitch(frame:CGRectMake(self.view.frame.width/2 - 20, 400, 10, 100))
switch1.on = true
switch1.onTintColor = UIColor.lightGrayColor()
switch1.tintColor = UIColor.greenColor()
switch1.thumbTintColor = UIColor.blackColor()
//set on/off image
switch1.onImage = UIImage(named: "on-switch")
switch1.offImage = UIImage(named: "off-switch")
Use a UIButton instead.
let switchButton = UIButton(type: .Custom)
switchButton.selected = true
switchButton.setImage(UIImage(named: "on-switch"), forState: .Selected)
switchButton.setImage(UIImage(named: "off-switch"), forState: .Normal)
Use switchButton.isSelected instead of switch1.on. You'll have to toggle switchButton.isSelected when it is tapped, which you can do like this:
switchButton.isSelected.toggle()
For iOS 13, you could do this way:
let switcher = UISwitch()
switcher.addTarget(self, action: #selector(pressed), for: .valueChanged)
#objc func pressed(sender: UISwitch) {
let color = UIColor(patternImage: UIImage(named: sender.isOn ? "on.png": "off.png")!)
if sender.isOn {
sender.onTintColor = color
} else {
sender.tintColor = color
sender.subviews[0].subviews[0].backgroundColor = color
}
}
NOTE: your image should look like:
Then the final result is:
Not an exact answer to your question, but if you want a completely custom button switch programmatically (that you can add text to), this will work too:
import UIKit
class RDHiddenVisibleButton: UIButton {
// Hidden / Visible Button Function
var isOn = false
override init(frame: CGRect) {
super.init(frame: frame)
initButton()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
initButton()
}
func initButton() {
layer.borderWidth = 2.0
layer.borderColor = Colors.radiusGreen.cgColor
layer.cornerRadius = frame.size.height/2
setTitleColor(Colors.radiusGreen, for: .normal)
addTarget(self, action: #selector(RDHiddenVisibleButton.buttonPressed), for: .touchUpInside)
}
#objc func buttonPressed() {
activateButton(bool: !isOn)
}
func activateButton(bool: Bool) {
isOn = bool
let color = bool ? Colors.radiusGreen : .clear
let title = bool ? "Hidden" : "Visible"
let titleColor = bool ? . white : Colors.radiusGreen
setTitle(title, for: .normal)
setTitleColor(titleColor, for: .normal)
backgroundColor = color
}
}

From SWIFT Playground to custom View (IBDesignable?)

Question:
I've written a custom View Component in a playground but I can't figure out how to turn it into a custom class that I can use in the Interface Builder. Specifically, I'm confused as to how to make sure my custom view will resize correctly as the IB view is changed
Sub Question
I would also like to be able to use the #IBDesignable/#IBInspectable functionality as well if possible
Playground Code
import UIKit
let labelWidth : CGFloat = 200.0
var viewWidth : CGFloat = 200.0
let labelHeight: CGFloat = 60.0
var viewHeight : CGFloat = 60.0
let xOffset : CGFloat = 20
let yOffset : CGFloat = 20
let label = UILabel(frame: CGRectMake(0, 0 + 10, labelWidth, 50))
label.text = "Custom Text"
label.backgroundColor = UIColor.greenColor()
label.layer.masksToBounds = true
//label.layer.cornerRadius = 10.0
label.textAlignment = NSTextAlignment.Center
label
let titleLabel = UILabel(frame: CGRectMake(0,0,labelWidth,20))
titleLabel.font = UIFont(name: label.font.fontName, size: 10)
titleLabel.text = " TITLE"
titleLabel.layer.masksToBounds = true
titleLabel.backgroundColor = UIColor.whiteColor()
titleLabel
let v = UIView(frame: CGRectMake(0, 0, viewWidth, viewHeight))
v.backgroundColor = UIColor.grayColor()
v.addSubview(label)
v.addSubview(titleLabel)
v.layer.borderWidth = 1
v.layer.borderColor = UIColor.redColor().CGColor
v
Playground Visual Output
Note: Obviously these are not the final colors i want to use but they help differentiate the components
I just posted this answer for a similar question.
Here is a sample class to get you started.
import UIKit
#IBDesignable
class MyTabView: UIView {
#IBInspectable tabTitle: String = ""
#IBInspectable tabColor: UIColor = UIColor.clearColor()
override init(frame: CGRect) {
super.init(frame: frame)
// Initialization code
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func prepareForInterfaceBuilder() {
// stuff for interface builder only
}
override func drawRect(rect: CGRect)
{
// this is where your view gets drawed
self.layer.cornerRadius = 10
self.layer.masksToBounds = true
}
}
Note: you only need to override drawRect if you need custom drawing.

Resources