UISwitch set on/off Image - xcode

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
}
}

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
}
-----
-----
}

How to get a custom tab bar to display a tab bar item's selected image set in Xcode?

I've created a custom tab bar that is displaying tab bar items correctly. When I select a tab / icon the tab bar item's view controller is displayed but the icon does not change to the 'Selected image' icon i.e. the icons don't change when their view controller is being shown.
What am I doing wrong? How can I get the icons to update to the images that I've set on IB as the selected images?
Here is some of my code:
class CustomTabBarController: UITabBarController, CustomTabBarDataSource, CustomTabBarDelegate {
override func viewDidLoad() {
super.viewDidLoad()
self.tabBar.isHidden = true
let customTabBar = CustomTabBar(frame: self.tabBar.frame)
customTabBar.datasource = self
customTabBar.delegate = self
customTabBar.setup()
self.view.addSubview(customTabBar)
}
// MARK: - CustomTabBarDataSource
func tabBarItemsInCustomTabBar(_ tabBarView: CustomTabBar) -> [UITabBarItem] {
return tabBar.items!
}
// MARK: - CustomTabBarDelegate
func didSelectViewController(_ tabBarView: CustomTabBar, atIndex index: Int) {
self.selectedIndex = index
}
}
class CustomTabBar: UIView {
var tabBarItems: [UITabBarItem]!
var customTabBarItems: [CustomTabBarItem]!
var tabBarButtons: [UIButton]!
func setup() {
tabBarItems = datasource.tabBarItemsInCustomTabBar(self)
customTabBarItems = []
tabBarButtons = []
let containers = createTabBarItemContainers()
createTabBarItems(containers)
}
func createTabBarItems(_ containers: [CGRect]) {
var index = 0
for item in tabBarItems {
let container = containers[index]
let customTabBarItem = CustomTabBarItem(frame: container)
customTabBarItem.setup(item)
self.addSubview(customTabBarItem)
customTabBarItems.append(customTabBarItem)
let button = UIButton(frame: CGRect(x: 0, y: 0, width: container.width, height: container.height))
button.addTarget(self, action: #selector(CustomTabBar.barItemTapped(_:)), for: UIControlEvents.touchUpInside)
customTabBarItem.addSubview(button)
tabBarButtons.append(button)
index += 1
}
}
func barItemTapped(_ sender : UIButton) {
let index = tabBarButtons.index(of: sender)!
delegate.didSelectViewController(self, atIndex: index)
}
Change
class CustomTabBar: UIView {
to:
class CustomTabBar: UITabBar {
Then your custom tab bar will act like a tab bar!
Well I had a same kind of functionality and implemented with UITabBarController like this.
enum TabType:Int{
case viewController1 = 0
case viewController2 = 1
case viewController3 = 2
}
class CustomTabbarVC: UITabBarController {
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
convenience init(userType : UserType){
self.init()
addViewControllers()
setupOnInit()
let tabBar = self.tabBar
tabBar.selectionIndicatorImage = UIImage().createSelectionIndicator(UIColor(red: 22/255, green: 52/255, blue: 89/255, alpha: 1.0), size: CGSize(width: tabBar.frame.width/CGFloat(tabBar.items!.count), height: tabBar.frame.height), lineWidth: 3.0)
}
func setupOnInit(){
delegate = self
tabBar.barStyle = UIBarStyle.black
tabBar.isTranslucent = false
}
func addViewControllers(){
// We will add 3 controllers
let viewController1 = viewController1(nibName: “viewController1”, bundle: nil)
let viewController2 = viewController2(nibName: “viewController2”, bundle: nil)
let viewController3 = viewController3(nibName: “viewController3”, bundle: nil)
let viewController1Navigation = UINavigationController(rootViewController: viewController1)
viewController1Navigation.tabBarItem = getTabbarItem(.viewController1)
viewController1Navigation.tabBarItem.imageInsets = UIEdgeInsetsMake(6, 0, -6, 0)
let viewController2Navigation = UINavigationController(rootViewController: viewController2)
viewController2Navigation.tabBarItem = getTabbarItem(.viewController2)
viewController2Navigation.tabBarItem.imageInsets = UIEdgeInsetsMake(6, 0, -6, 0)
let viewController3Navigation = UINavigationController(rootViewController: viewController3)
viewController3Navigation.tabBarItem = getTabbarItem(.viewController3)
viewController3Navigation.tabBarItem.imageInsets = UIEdgeInsetsMake(6, 0, -6, 0)
viewControllers = [viewController1Navigation,viewController2Navigation,viewController3Navigation]
}
func getTabbarItem(_ tabType:TabType)->UITabBarItem{
// Fetch tab bar item and set image according to it.
var image = String()
var selectedImage = String()
if tabType == .viewController1{
image = “img_viewController1_tab_nonSelected”
selectedImage = “img_viewController1_tab_Selected”
}else if tabType == .viewController2{
image = “img_viewController2_tab_nonSelected”
selectedImage = “img_viewController2_tab_Selected”
}else if tabType == .viewController3{
image = “img_viewController3_tab_nonSelected”
selectedImage = “img_viewController3_tab_Selected”
}else{
print("Unknown tab type")
}
if let imageName:String = image,let selectedImageName:String = selectedImage{
return UITabBarItem(title: nil, image: UIImage(named: imageName)?.withRenderingMode(.alwaysOriginal), selectedImage: UIImage(named: selectedImageName)?.withRenderingMode(.alwaysOriginal))
}else{
return UITabBarItem()
}
}
}
extension UIImage {
func createSelectionIndicator(_ color: UIColor, size: CGSize, lineWidth: CGFloat) -> UIImage {
UIGraphicsBeginImageContextWithOptions(size, false, 0)
color.setFill()
UIRectFill(CGRect(x: 0, y: size.height - lineWidth, width: size.width, height: lineWidth))
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image!
}
}
How to implement in App delegate
class AppDelegate: UIResponder, UIApplicationDelegate{
var window: UIWindow?
var customTabbarVC: CustomTabbarVC?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
window = UIWindow(frame: UIScreen.main.bounds)
customTabbarVC = customTabbarVC() // It will invoke init methods of customtabbarvc
window?.rootViewController = customTabbarVC // Here your tab bar controller will setup
return true
}
// Other APP DELEGATE METHODS
}
Let me know if you have any questions..
For Changing image in your custom tab bar button after you click the button you need to write the code to change image in below function
func barItemTapped(_ sender : UIButton) {
}
similarly
func barItemTapped(_ sender : UIButton)
{
if sender.tag == 1
{
tabBarButtons.setImage(UIImage(named:"FirstImage.png"), forState: .Normal)
}
else
{
tabBarButtons.setImage(UIImage(named:"SecImage.png"), forState: .Normal)
}
}

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
}
}

Swift - GLKit View CIFilter Image

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)

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