How can I verify the object type?
the goal is to check an object custom type to check the value
#IBAction func showAnswer(_ sender: UIButton) {
let question: Question = questions[currentQuestionIndex]
let rightAnswer = question.answers![question.answer]
let subViews = self.view.subviews
subViews.forEach { view in
if view.isMember(of: AnswerButton.self) {
let btn = view as! AnswerButton
if btn.titleLabel!.text == rightAnswer {
btn.hightlight()
}
}
}
}
this is the UI. the button with the right answer should highlight if this is the right answer.
enter image description here
Instead of
if view.isMember(of: AnswerButton.self) {
let btn = view as! AnswerButton
if btn.titleLabel!.text == rightAnswer {
btn.hightlight()
}
}
Use conditional downcasting:
if let btn = view as? AnswerButton {
// btn could be accessed as an instance of `AnswerButton` now
if btn.titleLabel!.text == rightAnswer {
btn.hightlight()
}
}
If you don't need to downcast the button then you can loop over the subviews with condition:
for view in subviews where view is AnswerButton {
// view is still treated as an instance of UIView but could be downcast to AnswerButton
}
Related
How to get imageView from UITabBar specific items. From below code its highlight enter specific section View.
I need to highlight More Tab only UIImageView for CoachMark.
How to get UIImageView value from UITabBar ?
guard let view = self.tabBarController?.tabBar.items?.last?.value(forKey: "view") as? UIView else{
return coachMarksController.helper.makeCoachMark()
}
// let imageView = view.subviews.compactMap { $0 as? UIImageView }.first
// return coachMarksController.helper.makeCoachMark(for: imageView) // Fails
return coachMarksController.helper.makeCoachMark(for: view)
Add these extensions to your app.
import UIKit
public extension UITabBar {
var tabBarButtons: [UIView] {
let values = self.subviews.filter({ String(describing: type(of: $0)) == "UITabBarButton" })
return values.sorted(by: { $0.frame.origin.x < $1.frame.origin.x })
}
}
public extension UIView {
var tabBarSwappableImageViews: [UIView] {
let values = self.subviews.filter({ String(describing: type(of: $0)) == "UITabBarSwappableImageView" })
return values.sorted(by: { $0.frame.origin.x < $1.frame.origin.x })
}
}
Then call this on your tab bar controller
let imageView: UIImageView? = UITabBarController?.tabBar.tabBarButtons[YOUR_INDEX_HERE].tabBarSwappableImageViews.first
I wanted to create a pop up for one of my UIViewController and found this repo on GitHub.
It is working fine with my InfoViewController which only has 4 UILabels (I think this might be the problem that it is not showing up when you use reusable cells)
But somehow it is not working with my StructureNavigationListViewController and I do not know why.
I call the didTapCategory method in my MainViewController where the StructureNavigationController should pop up but I only see the dimming view (which is weird cause the tap recognizer and pan gestures are working fine but no content is showing up)
In my MainViewController I set up the popup like before:
#IBAction func didTapCategory(_ sender: UIBarButtonItem) {
let popupContent = StructureNavigationListViewController.create()
let cardpopUp = SBCardPopupViewController(contentViewController: popupContent)
cardpopUp.show(onViewController: self)
}
In my StructureNavigationListViewController I set up the table view and the pop up:
public var popupViewController: SBCardPopupViewController?
public var allowsTapToDismissPopupCard: Bool = true
public var allowsSwipeToDismissPopupCard: Bool = true
static func create() -> UIViewController {
let sb = UIStoryboard(name: "Main", bundle: nil)
let vc = sb.instantiateViewController(withIdentifier: "StructureNavigationListViewController") as! StructureNavigationListViewController
return vc
}
#IBOutlet var tableView: UITableView!
var structures = Variable<[Structure]>([])
public var treeSource: StructureTreeSource?
let disposeBag = DisposeBag()
var depthDictionary : [String : Int] = [:]
public override func viewDidLoad() {
structures.asObservable()
.bind(to:tableView.rx.items) {(tableView, row, structure) in
let cell = tableView.dequeueReusableCell(withIdentifier: "StructureNavigationCell", for: IndexPath(row: row, section: 0)) as! StructureNavigationCell
cell.structureLabel.text = structure.name
cell.spacingViewWidthConstraint.constant = 20 * CGFloat(self.depthDictionary[structure.id]!)
return cell
}.disposed(by:disposeBag)
_ = tableView.rx.modelSelected(Structure.self).subscribe(onNext: { structure in
let storyBoard = UIStoryboard(name:"Main", bundle:nil)
let plansViewCtrl = storyBoard.instantiateViewController(withIdentifier: "PlansViewController2") as! PlansViewController2
self.treeSource?.select(structure)
plansViewCtrl.treeSource = self.treeSource
plansViewCtrl.navigationItem.title = structure.name
self.show(plansViewCtrl, sender: self)
if let mainVC = self.parent as? ProjectOverViewTabController2 {
mainVC.addChildView(viewController: plansViewCtrl, in: mainVC.scrollView)
}
})
showList()
}
func showList() {
if treeSource == nil {
treeSource = StructureTreeSource(projectId:GlobalState.selectedProjectId!)
}
//The following piece of code achieves the correct order of structures and their substructures.
//It is extremely bad designed and rather expensive with lots of structures and should
//therefore be refactored!
if let strctrs = getStructures() {
var sortedStructures : [Structure] = []
while(sortedStructures.count != strctrs.count) {
for strct in strctrs {
if let _ = sortedStructures.index(of: strct) {
continue
} else {
depthDictionary[strct.id] = getDepthOfNode(structure: strct, depth: 1)
if let structures = getStructures() {
if let parent = structures.first(where: {$0.id == strct.parentId}) {
if let index = sortedStructures.index(of: parent) {
sortedStructures.insert(strct, at: index+1)
}
} else {
sortedStructures.insert(strct, at: 0)
}
}
}
}
}
structures.value = sortedStructures
tableView.reloadData()
}
}
func getDepthOfNode(structure: Structure, depth: Int) -> Int {
if(structure.parentId == nil || structure.parentId == "") {
return depth
} else {
if let structures = getStructures() {
if let parent = structures.first(where: {$0.id == structure.parentId}) {
return getDepthOfNode(structure: parent, depth: depth + 1)
}
}
}
return -1
}
private func getStructures() -> Results<Structure>? {
do {
if let projectId = GlobalState.selectedProjectId {
return try Structure.db.by(projectId: projectId)
}
} catch { Log.db.error(error: error) }
return nil
}
}
Lot of code here. Sorry..
Is it because I call the create() method after the viewDidLoad() dequeues the cells?
It's hard to tell what is the problem, since you left no information about where didTapCategory is supposed to be called, but maybe it has something to do with your modelSelected subscription being prematurely released?
Edit:
As posted here: https://stackoverflow.com/a/28896452/11851832 if your custom cell is built with Interface Builder then you should register the Nib, not the class:
tableView.registerNib(UINib(nibName: "CustomCell", bundle: nil), forCellReuseIdentifier: "CustomCellIdentifier")
I try to implement search behavior like in Xcode: if you enter something in search field, icon changes color.
I delegate both searchFieldDidStartSearching and searchFieldDidEndSearching to controller and change the image.
The problem is icon's image changes only when window lose it's focus.
class ViewController: NSViewController {
#IBOutlet weak var searchField: NSSearchField!
func searchFieldDidStartSearching(_ sender: NSSearchField) {
print("\(#function)")
(searchField.cell as! NSSearchFieldCell).searchButtonCell?.image = NSImage.init(named: "NSActionTemplate")
}
func searchFieldDidEndSearching(_ sender: NSSearchField) {
print("\(#function)")
(searchField.cell as! NSSearchFieldCell).searchButtonCell?.image = NSImage.init(named: "NSHomeTemplate")
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override var representedObject: Any? {
didSet {
// Update the view, if already loaded.
}
}
}
Thanks in advance for any ideas/suggestions.
Although I don't know the reason, it works:
NSApp.mainWindow?.resignMain()
NSApp.mainWindow?.becomeMain()
Here is the whole code:
class MyViewController: NSViewController {
private lazy var searchField: NSSearchField = {
let searchField = NSSearchField(string: "")
if let searchButtonCell = searchField.searchButtonCell {
searchButtonCell.setButtonType(.toggle)
let filterImage = #imageLiteral(resourceName: "filter")
searchButtonCell.image = filterImage.tinted(with: .systemGray)
searchButtonCell.alternateImage = filterImage.tinted(with: .systemBlue)
}
searchField.focusRingType = .none
searchField.bezelStyle = .roundedBezel
searchField.delegate = self
return searchField
}()
...
}
extension MyViewController: NSSearchFieldDelegate {
func searchFieldDidStartSearching(_ sender: NSSearchField) {
sender.searchable = true
}
func searchFieldDidEndSearching(_ sender: NSSearchField) {
sender.searchable = false
}
}
extension NSSearchField {
var searchButtonCell: NSButtonCell? {
(self.cell as? NSSearchFieldCell)?.searchButtonCell
}
var searchable: Bool {
get {
self.searchButtonCell?.state == .on
}
set {
self.searchButtonCell?.state = newValue ? .on : .off
self.refreshSearchIcon()
}
}
private func refreshSearchIcon() {
NSApp.mainWindow?.resignMain()
NSApp.mainWindow?.becomeMain()
}
}
extension NSImage {
func tinted(with color: NSColor) -> NSImage? {
guard let image = self.copy() as? NSImage else { return nil }
image.lockFocus()
color.set()
NSRect(origin: NSZeroPoint, size: self.size).fill(using: .sourceAtop)
image.unlockFocus()
image.isTemplate = false
return image
}
}
I was having the same issue. A simple override fixed this issue for me
extension NSSearchField{
open override func draw(_ dirtyRect: NSRect) {
super.draw(dirtyRect)
}
}
As you can see when you click inside the view it's still focussed on the search text field(as you can still type in it after you clicked underneath it). Since the change image is on when it loses focus, you should check if you clicked outside of the text field.
Solve problem by subclassing NSSearchFieldCell and assign this class to field's cell.
You don't even need to subclass NSSearchFieldCell.
When you create your NSSearchField from code, you can do something like this:
if let searchFieldCell = searchField.cell as? NSSearchFieldCell {
let image = NSImage(named: "YourImageName")
searchFieldCell.searchButtonCell?.image = image
searchFieldCell.searchButtonCell?.alternateImage = image // Optionally
}
If you're using storyboards, you can do the same in didSet of your #IBOutlet.
How to know my button selected or not in swift 3 .selected property not found.
when i type checkBtn.selected not found in Swift 3 (Xcode 8.0)
if let button = sender as? UIButton {
if button.selected {
// set selected
button.selected = true
} else {
// set deselected
button.selected = false
}
}
try this below code
if let button = sender as? UIButton {
if button.isSelected {
// set selected
button.isSelected = true
} else {
// set deselected
button.isSelected = false
}
}
For shorthand, try this
if let button = sender as? UIButton {
button.isSelected = !button.isSelected
}
In swift 3 you will have isSelected instead of selected. Your code looks fine just make a change.
if let button = sender as? UIButton {
if button.isSelected {
//for selected input
} else {
//for not selected input
}
button.isSelected = !button.isSelected //toggle the text box
}
#IBOutlet weak var btnCheckBox: UIButton!
#IBAction func btnCheckBoxClick(_ sender: UIButton) {
if btnCheckBox.isSelected {
btnCheckBox.isSelected = false
btnCheckBox.setImage(#imageLiteral(resourceName: "icon_checkbox_inactive"), for: .normal)
}else {
btnCheckBox.isSelected = true
btnCheckBox.setImage(#imageLiteral(resourceName: "icon_checkbox_active"), for: .normal)
}
}
It worked for me.
I am trying to pass data from my model in my file, CalculatorBrain, to a ViewController through a segue. The var that I am trying to pass is designated as a PropertyList as shown below:
var program: PropertyList { // guaranteed to be PropertyList
get {
return opStack.map { $0.description }
}
set {
if let opSymbols = newValue as? Array<String> {
var newOpStack = [Op]()
for opSymbol in opSymbols {
if let op = knownOps[opSymbol] {
newOpStack.append(op)
} else if let operand = NSNumberFormatter().numberFromString(opSymbol)?.doubleValue {
newOpStack.append(.Operand(operand))
}
}
opStack = newOpStack
}
}
}
This is a multiple MVC project, and the override segue function is in a ViewController called "CalculatorViewController." The function tries to pass the data from the model to the ViewController known as "GraphingViewController" like this:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
var destination: UIViewController? = segue.destinationViewController
if let navCon = destination as? UINavigationController {
destination = navCon.visibleViewController
}
if let gvc = destination as? GraphingViewController {
gvc.program = brain.program
}
}
I set-up the variable program in my GraphingViewController as follows:
var program: AnyObject?
When I press the button that calls the segue, it does fire. What happens is that the data in brain.program gets copied into gvc.program. However, it is then LOST to the model. I don't know why this happens. When I print the program out from the controller in the segue, I do see the program as it should be shown. However, when I print it anywhere after the segue, it has disappeared.
Why would data, after the override segue function is called, be removed?
EDIT: This is the delegate function in the GraphingViewController. When I print out brain.program from here, it doesn't print out the full opStack.
func graphForGraphView(xAxisValue: CGFloat, sender: GraphView) -> CGPoint? {
print("BRAIN PROGRAM 2: \(brain.program)")
brain.variableValues[brain.variableM] = 40.0
if let yValue = brain.returnEvaluate() {
print(yValue)
print("The returned value is: \(yValue)")
let point = CGPoint(x: 40.0, y: CGFloat(yValue))
if !point.x.isNormal || !point.y.isNormal {
return nil
} else {
return point
}
}
return nil
}