【问题标题】:UIBUTTON and picker viewUIBUTTON 和选择器视图
【发布时间】:2011-06-21 18:04:55
【问题描述】:

我想在用户点击按钮时显示一个选择器 我对 UIButton 进行了子类化并更改了它的 inputview 以便它是可写的。

我点击了这个链接http://nomtek.com/tips-for-developers/working-with-pickers/

我点击按钮,没有任何反应。如果我将 inputview 从按钮更改为 UITextField 效果很好。有什么想法吗? 谢谢 萨罗

【问题讨论】:

    标签: iphone uibutton uipickerview


    【解决方案1】:

    1) 创建 UIButton 的子类

    .h

    #import <UIKit/UIKit.h>
    
    @interface UIButtonAsFirstResponder : UIButton
    
    @property (strong, nonatomic) UIView *inputView;
    @property (strong, nonatomic) UIView *inputAccessoryView;
    
    @end
    

    .m

    #import "UIButtonAsFirstResponder.h"
    
    @implementation UIButtonAsFirstResponder
    
    - (BOOL) canBecomeFirstResponder
    {
        return YES;
    }
    
    @end
    

    2) 在您的视图控制器中设置inputView(如果需要,还设置inputAccessoryView)(到您的选择器或任何其他自定义视图)

    3) 在视图控制器中为按钮创建 IBAction

    - (IBAction)becom:(id)sender {
        [sender becomeFirstResponder];
    }
    

    如果您想移除键盘,请点击您的按钮:

    [button resignFirstResponder];
    

    或在视图控制器中:

    [self.view endEditing:YES];
    

    【讨论】:

    • 如果父类只有getter,则不能设置子类的inputView。您可以将其分配给您自己的变量,但这不会产生影响。
    【解决方案2】:

    这就是我在 Swift 3 中的做法(覆盖属性的规则与 Objective-C 不同)。

    我想要一个显示日期的按钮,并在点击按钮时从屏幕底部显示日期选择器,以允许用户编辑显示的日期。使用锚定在目标按钮上的弹出框相对容易做到这一点,但我的应用程序仅适用于 iPhone(不是 iPad),因此 UITextField-inputView 模式似乎更好(在 AppStore 应用程序上使用可能会违反 Human界面指南)。

    按钮子类:

    class EditableButton: UIButton {
    
        // This holds the assigned input view (superclass property is readonly)
        private var customInputView: UIView?
    
        // We override the superclass property as computed, and actually 
        // store into customInputView: 
        override var inputView: UIView? {
            get {
                return customInputView
            }
            set (newValue) {
                customInputView = newValue
            }
        }
    
        // Must be able to become first responder in order to 
        // get input view to be displayed:
        override var canBecomeFirstResponder: Bool {
            return true
        }
    
        // Setup becoming first responder on tap:
        required init?(coder aDecoder: NSCoder) {
            super.init(coder: aDecoder)
    
            self.addTarget(self, action: #selector(EditableButton.tap(_:)), for: .touchDown)
            // (Not sure if this creates a retain cycle; must investigate)
        }
    
        @IBAction func tap(_ sender: UIButton) {
            self.becomeFirstResponder()
        }
    } 
    

    查看控制器代码:

    class ViewController: UIViewController {
    
        // Set the appropriate subclass in the storyboard too!
        @IBOutlet weak var todayButton: EditableButton!
    
        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view.
    
            let datePicker = UIDatePicker()
            datePicker.datePickerMode = .date
            todayButton.inputView = datePicker
    
            let dateFormatter = DateFormatter()
            dateFormatter.dateFormat = "yyyy-MM-dd"
            todayButton.setTitle(dateFormatter.string(from: Date()), for: .normal)
    
            // Also hook an a target/action to the date picker's 
            // valueChanged event, to get notified of the user's input
            datePicker.addTarget(self, action: #selector(ViewController.changeDate(_:)), for: .valueChanged)
        }
    
        @IBAction func changeDate(_ sender: UIDatePicker) {
            // (update button title with formatted date)
            let dateFormatter = DateFormatter()
            dateFormatter.dateFormat = "yyyy-MM-dd"
            todayButton.setTitle(dateFormatter.string(from: sender.date), for: .normal)  
    
            // Dismiss picker:
            todayButton.resignFirstResponder()
        }
    }
    

    注意: 为简单起见,此代码将在指定日期后立即关闭日期选择器 - 即,每当您滚动任何轮子时。这可能不是您想要的:通常,用户一次指定一个日期(年、月等)。此实现不会让用户在关闭日期选择器之前完成指定所有日期组件。

    理想情况下,您应该添加一个UIToolbar 作为输入附件视图,并带有一个“完成”按钮来关闭输入视图(即,使按钮退出第一响应者)。这需要进一步修改 UIButton 子类(也可以容纳 inputAccessoryView),但应该是可行的。


    编辑:我可以确认输入附件视图也可以以与输入视图完全相同的方式附加到自定义 UIButton 子类:

    private var customInputAccessoryView: UIView?
    
    override var inputAccessoryView: UIView? {
        get {
            return customInputAccessoryView
        }
        set (newValue) {
            customInputAccessoryView = newValue
        }
    }
    

    现在,我是这样设置的:

    let datePicker = UIDatePicker()
    datePicker.datePickerMode = .date
    todayButton.inputView = datePicker
    
    let dateFormatter = DateFormatter()
    dateFormatter.dateFormat = "yyyy-MM-dd"
    todayButton.setTitle(dateFormatter.string(from: Date()), for: .normal)
    
    datePicker.addTarget(self, action: #selector(ViewController.changeDate(_:)), for: .valueChanged)
    
    let dateToolbar = UIToolbar(frame: CGRect.zero)
    dateToolbar.barStyle = .default
    
    let dateDoneButton = UIBarButtonItem(
            barButtonSystemItem: .done,
            target: self,
            action: #selector(ViewController.dateDone(_:)))
    let dateSpacer = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
    
    dateToolbar.items = [dateSpacer, dateDoneButton]
    dateToolbar.sizeToFit()
    todayButton.inputAccessoryView = dateToolbar
    

    并以两个单独的操作进行响应:

    @IBAction func changeDate(_ sender: UIDatePicker) {
        // Update button title in real time:
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "yyyy-MM-dd"
        todayButton.setTitle(dateFormatter.string(from: sender.date), for: .normal)
    }
    
    @IBAction func dateDone(_ sender: UIBarButtonItem) {
        // ...but dismiss picker only on 'Done': 
        todayButton.resignFirstResponder()
    }
    

    另外,当视图控制器从导航中弹出时,我的自定义按钮子类的deinit() 方法确实会被调用,因此UIButton 不再(?)保留其目标,或者Swift 运行时比我想象的要聪明...


    更新:我整理了一个Xcode project demonstrating this custom button(Github 存储库)。修改它以使用自定义UIPickerView(而不是UIDatePicker)应该非常简单。 不是立即显而易见的(至少对我而言)是如何使它与键盘一起作为输入视图工作。

    【讨论】:

      【解决方案3】:

      inputView 属性只是UITextField 和UITextView 的一部分,而不是UIButton。

         @property (readwrite, retain) UIView *inputView;
      

      虽然您可以使用UIButton 实现相同的效果。

      创建一个UIButton 对象,然后设置一个action 方法,并在UIButton 的action 方法中将您的选择器视图添加到按钮的父视图中。

      应该是这样的。

      -(void) buttonClicked:(id) sender
      {
          [self.view addSubview:myPickerView];
      }
      

      【讨论】:

      • 您是说当用户单击按钮时我无法显示选择器?我正在尝试模仿 c# 中的组合功能。用户在文本框中输入内容,然后如果她想查找列表,则按下下拉按钮。
      • 这很棒。但是我该如何显示呢?我在动作中有 myPicker.hidden = NO 但我没有看到它。谢谢
      • @Saro Khatchatourian : 你是否添加了选择器作为子视图并设置了选择器视图的框架?
      • 是的,我做到了。我做的一件事是将 hidden 设置为 yes 并显示出来。感谢敌人的帮助!
      • @Saro Khatchatourian:如果对您有帮助,请接受答案
      猜你喜欢
      • 2013-05-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-06-22
      相关资源
      最近更新 更多