I want to add a shadow to the background when UIPickerView is shown.
This is my
func setupPickerView() {
self.surveyTypeTextField.inputView = pickerView
self.surveyTypeTextField.inputAccessoryView = self.pickerView.toolbar
self.surveyTypeTextField.backgroundColor = KSColor.neutral050.getColor()
self.surveyTypeTextField.attributedPlaceholder = NSAttributedString(
string: "Seç",
attributes: [NSAttributedString.Key.foregroundColor: KSColor.neutral700.getColor(),
NSAttributedString.Key.font: UIFont.sfProTextMedium(size: 14)]
)
self.pickerView.delegate = self
self.pickerView.dataSource = self
self.pickerView.toolbarDelegate = self
self.surveyTypeTextField.textAlignment = .left
self.pickerView.reloadAllComponents()
self.pickerView.backgroundColor = KSColor.bwWhite.getColor()
}
I tried adding shadow inside here but it was ineffective.
func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
if textField == surveyTypeTextField {
return false
}
return true
}
i add about 20+ images to the stack and by tap on image i need to change borderColor, but with this code i have error " "-[__NSArray0 tapOnView]: unrecognized selector sent to instance "
Add stack here
private lazy var mainHStack: UIStackView = {
let stack = UIStackView()
stack.axis = .horizontal
stack.distribution = .fill
stack.spacing = 8
return stack
}()
Add constraints here
scrollView.addSubview(mainHStack)
mainHStack.snp.makeConstraints { make in
make.edges.equalToSuperview()
}
tapOnMediaView()
Configure stack here
func configureMediaViewer(withImages images: [String]) {
for image in images {
let imageView = UIImageView()
imageView.contentMode = .scaleAspectFill
imageView.layer.cornerRadius = 8
imageView.clipsToBounds = true
imageView.setImage(imageUrl: image)
mainHStack.addArrangedSubview(imageView)
imageView.snp.makeConstraints { make in
make.width.height.equalTo(60)
}
}
}
Check if i tapped on image here
func tapOnMediaView() {
let arrangedImages = mainHStack.arrangedSubviews
let tap = UITapGestureRecognizer(target: arrangedImages, action: #selector(tapOnView))
if let tag = tap.view?.tag {
let currentImage = mainHStack.arrangedSubviews[tag]
currentImage.layer.borderWidth = 1
currentImage.layer.borderColor = UIColor.orange.cgColor
}
addGestureRecognizer(tap)
}
TapOnView has a delegate
#objc func tapOnView() {
delegate?.tapOnView()
}
Delegate
protocol PhotosViewProtocol: AnyObject {
func tapOnView()
}
Extension for mainVC
extension MediaViewerViewController: PhotosViewProtocol {
func tapOnView() {
print("check if works")
//not works :C
}
}
how do i change my code to get a result?
By pressing a button in my app, the value of a variable falls by 3. While this happens without any issues, the label which uses string interpolation to show that variable as its text (label.text) does not reflect the change.
How can I make it so pressing the button changes the value of the UILabel?
import UIKit
class ViewController: UIViewController {
var token = 5
let theButton: UIButton = {
let button = UIButton(type: .system)
button.setTitle("button", for: .normal)
button.backgroundColor = .systemPink
button.addTarget(self, action: #selector(theButtonPressed), for: .touchUpInside)
button.translatesAutoresizingMaskIntoConstraints = false
return button
}()
#objc func theButtonPressed() {
if token >= 3 {
token -= 3
print("ok done")
} else {
print("nope")
}
}
lazy var tokenLabel: UILabel = {
let label = UILabel()
label.text = "\(token)"
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemBlue
view.addSubview(tokenLabel)
view.addSubview(theButton)
theButton.heightAnchor.constraint(equalToConstant: 100).isActive = true
theButton.widthAnchor.constraint(equalToConstant: 200).isActive = true
theButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
theButton.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
tokenLabel.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: 60).isActive = true
tokenLabel.heightAnchor.constraint(equalToConstant: 300).isActive = true
tokenLabel.widthAnchor.constraint(equalToConstant: 200).isActive = true
tokenLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
}
}
You need to update the label's text when the button is pressed.
#objc func theButtonPressed() {
if token >= 3 {
token -= 3
print("ok done")
tokenLabel.text = "\(token)" // <- update
} else {
print("nope")
}
}
Or, you can observe the property token and change the label when a new value is set.
var token = 5 {
didSet {
tokenLabel.text = "\(token)"
}
}
#objc func theButtonPressed() {
if token >= 3 {
token -= 3
print("ok done")
} else {
print("nope")
}
}
I solved the problem
override func viewDidLoad() {
super.viewDidLoad()
let save = UserDefaults.standard.bool(forKey: "RememberMe")
self.circleBox.isChecked = save
}
#objc func checkboxvalue(sender: Checkbox) {
if sender.isChecked == true {
labelcheckbox.text = ("Beni")
action((Any).self)
UserDefaults.standard.set(true, forKey:"RememberMe");
}else{
labelcheckbox.text = ("")
UserDefaults.standard.set(false, forKey:"RememberMe");
}
}
I've designed a recall checkbox. But when I log out of the application, I want the checkbox value to be set to UserDefaults as true or false. So I want the checkbox to remember true or false when I get into the application.
lazy var circleBox: Checkbox = {
let squareBox = Checkbox(frame: CGRect(x: 22, y: 290, width: 25, height: 25))
squareBox.tintColor = .black
squareBox.borderStyle = .square
squareBox.checkmarkStyle = .square
squareBox.uncheckedBorderColor = .lightGray
squareBox.borderWidth = 1
squareBox.addTarget(self, action: #selector(checkboxvalue(sender:)), for: .valueChanged)
return squareBox
}()
#objc func checkboxvalue(sender: Checkbox) {
if sender.isChecked == true {
labelcheckbox.text = ("Remember me")
action((Any).self)
}else{
labelcheckbox.text = ("Don't remember")
}
}
I have a custom view subclassing NSView, which is just an NSStackView containing a label, slider, a second label and a checkbox. The slider and checkbox are both configured to report changes to the view (and eventually, via a delegate to a ViewController):
fileprivate extension NSTextField {
static func label(text: String? = nil) -> NSTextField {
let label = NSTextField()
label.isEditable = false
label.isSelectable = false
label.isBezeled = false
label.drawsBackground = false
label.stringValue = text ?? ""
return label
}
}
#IBDesignable
class Adjustable: NSView {
private let sliderLabel = NSTextField.label()
private let slider = NSSlider(target: self, action: #selector(sliderChanged(_:)))
private let valueLabel = NSTextField.label()
private let enabledCheckbox = NSButton(checkboxWithTitle: "Enabled", target: self, action: #selector(enabledChanged(_:)))
var valueFormatter: (Double)->(String) = { String(format:"%5.2f", $0) }
...
#objc func sliderChanged(_ sender: Any) {
guard let slider = sender as? NSSlider else { return }
valueLabel.stringValue = valueFormatter(slider.doubleValue)
print("Slider now: \(slider.doubleValue)")
delegate?.adjustable(self, changedValue: slider.doubleValue)
}
#objc func enabledChanged(_ sender: Any) {
guard let checkbox = sender as? NSButton else { return }
print("Enabled now: \(checkbox.state == .on)")
delegate?.adjustable(self, changedEnabled: checkbox.state == .on)
}
}
Using InterfaceBuilder, I can add one instance of this to a ViewController by dragging in a CustomView and setting it's class in the Identity Inspector. Toggling the checkbox or changing the slider will have the desired effect.
However, if I have multiple instances then in the target-action functions self will always refer to the same instance of the view, rather than the one being interacted with. In other words, self.slider == sender is only true in sliderChanged for one of the sliders. While I can get the correct slider value via sender, I cannot update the correct label as self.valueLabel is always the label in the first instance of the custom view.
Incidentally, #IBDesignable and the code intended to support it have no effect so there's something I'm missing there too - Interface Builder just shows empty space.
The whole file:
import Cocoa
fileprivate extension NSTextField {
static func label(text: String? = nil) -> NSTextField {
let label = NSTextField()
label.isEditable = false
label.isSelectable = false
label.isBezeled = false
label.drawsBackground = false
label.stringValue = text ?? ""
return label
}
}
protocol AdjustableDelegate {
func adjustable(_ adjustable: Adjustable, changedEnabled: Bool)
func adjustable(_ adjustable: Adjustable, changedValue: Double)
}
#IBDesignable
class Adjustable: NSView {
var delegate: AdjustableDelegate? = nil
private let sliderLabel = NSTextField.label()
private let slider = NSSlider(target: self, action: #selector(sliderChanged(_:)))
private let valueLabel = NSTextField.label()
private let enabledCheckbox = NSButton(checkboxWithTitle: "Enabled", target: self, action: #selector(enabledChanged(_:)))
var valueFormatter: (Double)->(String) = { String(format:"%5.2f", $0) }
#IBInspectable
var label: String = "" {
didSet {
sliderLabel.stringValue = label
}
}
#IBInspectable
var value: Double = 0 {
didSet {
slider.doubleValue = value
valueLabel.stringValue = valueFormatter(value)
}
}
#IBInspectable
var enabled: Bool = false {
didSet {
enabledCheckbox.isEnabled = enabled
}
}
#IBInspectable
var minimum: Double = 0 {
didSet {
slider.minValue = minimum
}
}
#IBInspectable
var maximum: Double = 100 {
didSet {
slider.maxValue = maximum
}
}
#IBInspectable
var tickMarks: Int = 0
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
required init?(coder decoder: NSCoder) {
super.init(coder: decoder)
setup()
}
override func prepareForInterfaceBuilder() {
setup()
}
override func awakeFromNib() {
setup()
}
private func setup() {
let stack = NSStackView()
stack.orientation = .horizontal
stack.translatesAutoresizingMaskIntoConstraints = false
stack.addArrangedSubview(sliderLabel)
stack.addArrangedSubview(slider)
stack.addArrangedSubview(valueLabel)
stack.addArrangedSubview(enabledCheckbox)
sliderLabel.stringValue = label
slider.doubleValue = value
valueLabel.stringValue = valueFormatter(value)
slider.minValue = minimum
slider.maxValue = maximum
slider.numberOfTickMarks = tickMarks
// Make the slider be the one that expands to fill available space
slider.setContentHuggingPriority(NSLayoutConstraint.Priority(rawValue: 249), for: .horizontal)
sliderLabel.widthAnchor.constraint(equalToConstant: 60).isActive = true
valueLabel.widthAnchor.constraint(equalToConstant: 60).isActive = true
addSubview(stack)
stack.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
stack.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
stack.topAnchor.constraint(equalTo: topAnchor).isActive = true
stack.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
}
#objc func sliderChanged(_ sender: Any) {
guard let slider = sender as? NSSlider else { return }
valueLabel.stringValue = valueFormatter(slider.doubleValue)
print("Slider now: \(slider.doubleValue)")
delegate?.adjustable(self, changedValue: slider.doubleValue)
}
#objc func enabledChanged(_ sender: Any) {
guard let checkbox = sender as? NSButton else { return }
print("Enabled now: \(checkbox.state == .on)")
delegate?.adjustable(self, changedEnabled: checkbox.state == .on)
}
}
The solution, as described in the question linked by Willeke, was to ensure init had completed before referencing self. (I'm slightly surprised the compiler allowed it to be used in a property initialiser)
Wrong:
private let slider = NSSlider(target: self, action: #selector(sliderChanged(_:)))
private let enabledCheckbox = NSButton(checkboxWithTitle: "Enabled", target: self, action: #selector(enabledChanged(_:)))
Right:
private lazy var slider = NSSlider(target: self, action: #selector(sliderChanged(_:)))
private lazy var enabledCheckbox = NSButton(checkboxWithTitle: "Enabled", target: self, action: #selector(enabledChanged(_:)))