UIBUTTON 和选择器视图

发布于 2024-11-16 18:23:44 字数 293 浏览 3 评论 0原文

我想在用户单击按钮时显示选择器 我对 UIButton 进行了子类化并更改了其输入视图,使其可写。

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

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

I want to display a picker when the user clicks on a button
I subclassed the UIButton and changed its inputview so that it is writable.

I followed this link http://nomtek.com/tips-for-developers/working-with-pickers/

I clickon the button and nothing happens. If I change the inputview from the button to UITextField it works great. Any thoughts?
Thanks
Saro

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

尘世孤行 2024-11-23 18:23:45

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];

1) Create a subclass of a 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) Set inputView (if needed also inputAccessoryView) in your view controller (to your picker or any other custom view)

3) Create IBAction for your button in your view controller

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

If you want to remove keyboard, call on your button:

[button resignFirstResponder];

or in view controller:

[self.view endEditing:YES];
写下不归期 2024-11-23 18:23:45

这就是我在 Swift 3 中所做的(重写属性的规则与 Objective-C 不同)。

我想要一个显示日期的按钮,并在点击按钮时从屏幕底部显示日期选择器,以允许用户编辑显示的日期。使用锚定在目标按钮上的弹出窗口相对容易做到这一点,但我的应用程序仅适用于 iPhone(不是 iPad),因此 UITextField-inputView 模式似乎更好(在 AppStore 应用程序上使用,您需要承担违反人类行为准则的风险)接口指南)。

按钮子类:

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 项目演示此自定义按钮(Github 存储库)。修改它以使用自定义 UIPickerView (而不是 UIDatePicker)应该非常简单。 立即显而易见的是(至少对我而言)如何使其与键盘作为输入视图一起使用。

This is how I did it in Swift 3 (the rules for overriding properties are different from Objective-C).

I wanted a button that displays a date, and to display a date picker from the bottom of the screen on button tap, to allow the user to edit the date displayed. This is relatively easy to do with a popover anchored over the target button, but my app is iPhone-only (not iPad) so the UITextField-inputView pattern seems better (use on AppStore apps at your own risk of violating the Human Interface Guidelines).

Button subclass:

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

View Controller Code:

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

Note:
For simplicity, this code will dismiss the date picker as soon a date is specified -i.e., whenever you scroll any of the wheels. This might not be what you want: Typically, the user specifies a date one component at a time (year, month, etc.). This implementation won't let the user finish specifying all date components before dismissing the date picker.

Ideally, you would add a UIToolbar as an input accessory view, with a "done" button that dismisses the input view (i.e., causes the button to resign first responder). That would require further modification of the UIButton subclass (to also accommodate an inputAccessoryView), but should be doable.


EDIT: I can confirm that an input accessory view can also be attached to the custom UIButton subclass in the exact same way as the input view:

private var customInputAccessoryView: UIView?

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

Now, I set it up like this:

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

And respond with two separate actions:

@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()
}

Also, the deinit() method of my custom button subclass does get called when the view controller is popped out of the navigation so either UIButton no longer (?) retains its targets, or the Swift runtime is smarter than I thought...


UPDATE: I put together an Xcode project demonstrating this custom button (Github repository). It should be quite straightforward to modify it to work with a custom UIPickerView (instead of a UIDatePicker). What is not immediately obvious (to me, at least) is how to make it work with a keyboard as input view.

一花一树开 2024-11-23 18:23:45

inputView 属性只是 UITextFieldUITextView 的一部分,而不是 UIButton

   @property (readwrite, retain) UIView *inputView;

尽管您可以使用 UIButton 实现相同的效果。

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

应该是这样的。

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

The inputView property is only the part of UITextField and UITextView not UIButton.

   @property (readwrite, retain) UIView *inputView;

Although you could achieve the same using UIButton.

Create an UIButton object then set an action method and add your picker view in parent view of your button in the action method of UIButton.

Should be something like that.

-(void) buttonClicked:(id) sender
{
    [self.view addSubview:myPickerView];
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文