How to Add Shadow to ParentView When UIPickerView is Shown - swift

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
}

Related

pinch zoom image view inside the view only

I am trying to zoom image view inside a UIView, but it zoom outside the UIView.
Condition : without using scrollview
here is my code :
extension UIImageView {
func enableZoom() {
let pinchGesture = UIPinchGestureRecognizer(target: self, action: #selector(startZooming(_:)))
isUserInteractionEnabled = true
addGestureRecognizer(pinchGesture)
}
#objc
private func startZooming(_ sender: UIPinchGestureRecognizer) {
let scaleResult = sender.view?.transform.scaledBy(x: sender.scale, y: sender.scale)
guard let scale = scaleResult, scale.a > 1, scale.d > 1 else { return }
sender.view?.transform = scale
sender.scale = 1
}
}
lazy var ImgView : UIImageView = {
let i = UIImageView()
i.enableZoom()
return i
}()
lazy var topView : UIView = {
let c = UIView()
return c
}()
in viewdidload
self.view.layout(self.ImgView).top(90).left().right().height(topViewHeight)
self.topView = self. ImgView

Square UIImageView and UITextField in UITableViewCell

I'm trying to create a cell that contains a square UIImageView and a UITextField. If the text fits the width of the screen, then everything works fine. But as soon as I change the text to a longer one, the presentation breaks down. There are no messages in the console about the correctness of the constraints.
When the text in the UITextField fits on the screen or UITextField contains only placeholder everything works fine.
But if the text is long enough, the presentation breaks down.
The code with which I create the view:
extension TextFieldWithImageTVCell {
private func initView() {
selectionStyle = .none
initImgView()
initTextField()
contentView.addSubview(imgView)
contentView.addSubview(textField)
// debug code
imgView.backgroundColor = UIColor.black
textField.backgroundColor = UIColor.blue
}
private func initImgView() {
imgView = UIImageView(frame: CGRect.zero)
imgView.translatesAutoresizingMaskIntoConstraints = false
}
private func initTextField() {
textField = UITextField(frame: CGRect.zero)
textField.translatesAutoresizingMaskIntoConstraints = false
textField.isUserInteractionEnabled = false
}
}
The code with which I create constraints:
extension TextFieldWithImageTVCell {
private func initConstraints() {
initConstraintsImgView()
initConstraintsTextField()
}
private func initConstraintsImgView() {
imgView.heightAnchor.constraint(equalTo: imgView.widthAnchor).isActive = true
let margins = contentView.layoutMarginsGuide
imgView.leadingAnchor.constraint(equalTo: margins.leadingAnchor).isActive = true
imgView.topAnchor.constraint(equalTo: margins.topAnchor).isActive = true
imgView.bottomAnchor.constraint(equalTo: margins.bottomAnchor).isActive = true
}
private func initConstraintsTextField() {
textField.leadingAnchor.constraint(equalTo: imgView.trailingAnchor, constant: 8).isActive = true
let margins = contentView.layoutMarginsGuide
textField.topAnchor.constraint(equalTo: margins.topAnchor).isActive = true
textField.trailingAnchor.constraint(equalTo: margins.trailingAnchor).isActive = true
textField.bottomAnchor.constraint(equalTo: margins.bottomAnchor).isActive = true
}
}
The part of code with which I configure cell:
cell.textContent = subject
cell.placeholder = "Предмет"
cell.isEditingEnabled = true
guard let textField = cell.textField else {
assertionFailure("error in ItemSubject::configureCellForRow")
return
}
textField.delegate = self
textField.clearButtonMode = .always
textField.adjustsFontSizeToFitWidth = true
textField.minimumFontSize = 10
Cell properties:
extension TextFieldWithImageTVCell {
var placeholder: String? {
set { textField.placeholder = newValue }
get { return textField.placeholder }
}
var textContent: String? {
set { textField.text = newValue }
get { return textField.text }
}
var isEditingEnabled: Bool {
set { textField.isUserInteractionEnabled = newValue }
get { return textField.isUserInteractionEnabled }
}
}
What constraints do I need to add to achieve the desired result?
Why are my constraints not enough?

UIImageView isUserInteractionEnabled = true doesn't work

The following DateField class has a date field and an icon on it. For some reason fieldIcon.isUserInteractionEnabled = true has zero affect and doesn't pass user tap to the field. Am I missing something?
import UIKit
import SnapKit
protocol DateFieldDelegate: class {
func dateSelected(_ dateField: DateField, date: Date)
}
class DateField: UIView, UITextFieldDelegate {
weak var delegate: DateFieldDelegate?
let field = UITextField()
private var datePicker: UIDatePicker?
convenience init(withStartDate startDate: Date) {
self.init()
datePicker = prepareDatePicker()
guard let datePicker = datePicker else { return }
field.inputView = datePicker
field.delegate = self
addSubview(field)
field.snp.makeConstraints { make in
make.top.equalToSuperview()
make.leading.equalToSuperview()
make.trailing.equalToSuperview()
make.height.equalTo(37)
make.bottom.equalToSuperview()
}
let fieldIcon = UIImageView(image: UIImage(asset: Asset.calendar))
field.addSubview(fieldIcon)
fieldIcon.isUserInteractionEnabled = true // doesn't work
fieldIcon.snp.makeConstraints { make in
make.width.equalTo(21)
make.height.equalTo(23)
make.trailing.equalToSuperview().offset(-10)
make.centerY.equalToSuperview()
}
setStyle(.regular)
}
func textFieldDidEndEditing(_ textField: UITextField) {
guard let date = datePicker?.date else { return }
field.text = date.formatToString()
delegate?.dateSelected(self, date: date)
}
private func prepareDatePicker() -> UIDatePicker {
let datePicker = UIDatePicker()
datePicker.datePickerMode = .date
datePicker.setDate(Date(), animated: false)
datePicker.locale = Language.appLocale()
return datePicker
}
}
Not sure if I've missed something in your code but you need to add some kind of action to the image, enabling userInteractionEnabled does not tell it to recognise taps on the item and what to do when this happens. You need to add a UITapGestureRecogniser to the UIImageView
let fieldIcon = UIImageView(image: UIImage(asset: Asset.calendar))
field.addSubview(fieldIcon)
fieldIcon.isUserInteractionEnabled = true // doesn't work
let fieldIcon = UIImageView(image: UIImage(asset: Asset.calendar))
field.addSubview(fieldIcon)
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(calenderIconTapped))
fieldIcon.addGestureRecognisor(tapGesture)
func calenderIconTapped() {
// show the picker
}
UPDATE:
After re-reading your question, I understand what your attempting to do now. If you want any taps on the image view to passthrough to the UITextField underneath you need to do the opposite of what you tried... you need to set userInteractionEnabled to false on the UIImageView
fieldIcon.isUserInteractionEnabled = false

Target-Action problems with custom view built from standard views

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(_:)))

swift - change label in header when UI Switch changes in the Navigation Bar

I want to change the label in my header to correlate with my UISwitch
though I have have no success as yet?
setLeftNavButton() is called in viewDidLoad()
func setLeftNavButton() {
let switchControl=UISwitch()
//switchControl.isOn = true
//switchControl.setOn(true, animated: false)
switchControl.addTarget(self, action: #selector(switchValueDidChange), for: .valueChanged)
self.navigationItem.leftBarButtonItem = UIBarButtonItem.init(customView: switchControl)
self.switchControl = switchControl
}
var switchControl: UISwitch?
func switchValueDidChange(){
guard let mySwitch = switchControl else { return }
if mySwitch.isOn {
header?.onlineOfflineStatusLabel.text = "on"
}
else {
header?.onlineOfflineStatusLabel.text = "off"
}
self.header?.reloadInputViews()
self.collectionView?.reloadData()
}
try this:
func setLeftNavButton() {
let switchControl = UISwitch()
switchControl.addTarget(self, action: #selector(switchValueDidChange(_:)), for: .valueChanged)
self.navigationItem.leftBarButtonItem = UIBarButtonItem.init(customView: switchControl)
self.switchControl = switchControl
}
#objc
func switchValueDidChange(_ sender: UISwitch){
if sender.isOn {
header?.onlineOfflineStatusLabel.text = "on"
} else {
header?.onlineOfflineStatusLabel.text = "off"
}
self.header?.reloadInputViews()
self.collectionView?.reloadData()
}