【问题标题】:UILabel doesn't show inputViewUILabel 不显示 inputView
【发布时间】:2012-10-11 21:54:52
【问题描述】:

我会使用 UILabel 来允许用户使用 UIDatePicker 选择日期。

为此,我创建了一个 UILabel 子类,覆盖了 inputView 和 inputAccessoryView 属性,使它们可写;我还实现了 -(BOOL) canBecomeFirstResponder 和 -(BOOL) isUserInteractionEnabled 方法,两者都返回 YES。 然后我将一个 UIDatePIcker 实例分配给 inputView 属性。

此时我的期望是,当点击标签时,应该会出现一个 UIDatePicker,但什么也没有发生。

有什么帮助吗?

这是代码:

YPInteractiveUILabel.h

@interface YPInteractiveUILabel : UILabel
    @property (readwrite) UIView *inputView;
    @property (readwrite) UIView *inputAccessoryView;

- (BOOL) canBecomeFirstResponder;
- (BOOL) isUserInteractionEnabled;
@end


YPInteractiveUILabel.h

#import "YPInteractiveUILabel.h"

@implementation YPInteractiveUILabel

- (id)initWithCoder:(NSCoder *)aDecoder
{
    self = [super initWithCoder:aDecoder];

    if (self)
    {
        UIDatePicker *datePicker = [[UIDatePicker alloc] init];
        [self  setInputView:datePicker];
    }

    return self;
}

- (BOOL)isUserInteractionEnabled
{
    return YES;
}

- (BOOL)canBecomeFirstResponder
{
    return YES;
}

@end

【问题讨论】:

  • 尝试在init方法中加入self.userInteractionEnabled = YES。
  • 为什么不使用 UITextField 呢?
  • @jsd 我试过了,还是不行。
  • @rdelmar 因为我不想在显示日期选择器时向用户显示 UITextField 光标。
  • @Massimiliano 在某人视图下隐藏文本字段,然后调用 becomeFirstResponder

标签: objective-c ios xcode


【解决方案1】:

UILabel + UIDatePicker -- 带有完成按钮的 Swift 版本。

import UIKit

class DatePickerLabel: UILabel {

    private let _inputView: UIView? = {
        let picker = UIDatePicker()
        return picker
    }()

    private let _inputAccessoryToolbar: UIToolbar = {
        let toolBar = UIToolbar()
        toolBar.barStyle = UIBarStyle.Default
        toolBar.translucent = true

        toolBar.sizeToFit()

        return toolBar
    }()

    override var inputView: UIView? {
        return _inputView
    }

    override var inputAccessoryView: UIView? {
        return _inputAccessoryToolbar
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)

        let doneButton = UIBarButtonItem(title: "Done", style: UIBarButtonItemStyle.Plain, target: self, action: #selector(doneClick))
        let spaceButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.FlexibleSpace, target: nil, action: nil)

        _inputAccessoryToolbar.setItems([ spaceButton, doneButton], animated: false)

        let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(launchPicker))
        self.addGestureRecognizer(tapRecognizer)
    }

    override func canBecomeFirstResponder() -> Bool {
        return true
    }

    @objc private func launchPicker() {
        becomeFirstResponder()
    }

    @objc private func doneClick() {
        resignFirstResponder()
    }

}

【讨论】:

    【解决方案2】:

    您可以只覆盖 inputView getter 方法,如 Apple documentation 中所述:

    - (UIView *)inputView {
        return myInputView;
    }
    - (BOOL)canBecomeFirstResponder {
        return YES;
    }
    

    然后添加手势或按钮调用 becomeFirstResponder:

    - (void)showInputView:(id)sender {
         [self becomeFirstResponder];
    }
    

    【讨论】:

      【解决方案3】:

      这样的事情怎么样。与其子类化标签,只需为其添加一个手势识别器,并在点击识别器的处理程序中调出选择器。在选取器的操作方法中,填充标签并关闭选取器。此示例有效,但您可能需要添加一些动画以使其看起来更好:

      - (void)viewDidLoad {
          [super viewDidLoad];
          self.label.userInteractionEnabled = YES;
          UITapGestureRecognizer *tapper = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(launchPicker:)];
          [self.label addGestureRecognizer:tapper];
      }
      
      -(void)launchPicker:(UITapGestureRecognizer *) tapper {
          UIDatePicker *picker = [[UIDatePicker alloc] initWithFrame:CGRectMake(5, 150, 300, 200)];
          [picker addTarget:self action:@selector(updateLabel:) forControlEvents:UIControlEventValueChanged];
          [self.view addSubview:picker];
      }
      
      -(IBAction)updateLabel:(UIDatePicker *)sender {
          self.label.text = [NSString stringWithFormat:@"%@",sender.date ];
          [sender removeFromSuperview];
      }
      

      【讨论】:

      • 这看起来在技术上是可行的,但只是添加一个子视图会......不优雅。当然,你可以让它看起来像一个原生输入视图,但是你正在重新发明轮子。仍在寻找一个好的解决方案来使 UIDatePicker 与 UILabel 一起玩得很好,就像它与 UIText Field =(
      【解决方案4】:

      感谢建议(尤其是 NeverBe 的评论和 rdelmar 提出的答案),我在代码中发现了问题。 简而言之,为了显示输入标签,需要在用户点击标签时调用 becomeFirstResponder 方法。

      在更正了 UILabel 子类实现之后(头文件保持不变):

      @implementation YPInteractiveUILabel
      
      - (id)initWithCoder:(NSCoder *)aDecoder
      {
          self = [super initWithCoder:aDecoder];
      
          if (self)
          {
              UIDatePicker *datePicker = [[UIDatePicker alloc] init];
              [self  setInputView:datePicker];
      
              UITapGestureRecognizer *tapper = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(launchPicker:)];
              [self addGestureRecognizer:tapper];
      
          }
      
          return self;
      }
      
      - (BOOL)isUserInteractionEnabled
      {
          return YES;
      }
      
      - (BOOL)canBecomeFirstResponder
      {
          return YES;
      }
      
      -(void)launchPicker:(UITapGestureRecognizer *) tapper
      {
          [self becomeFirstResponder];
      }
      
      
      @end
      

      【讨论】:

      • 也许这在某些时候有效,但 inputView 现在是只读的。
      【解决方案5】:

      这是更新到 Swift 5 的 @dmitriy-kirakosyan 的代码片段

      class DatePickerLabel: UILabel {
      
          private let _inputView: UIView? = {
              let picker = UIDatePicker()
              return picker
          }()
      
          private let _inputAccessoryToolbar: UIToolbar = {
              let toolBar = UIToolbar()
              toolBar.barStyle = UIBarStyle.default
              toolBar.isTranslucent = true
      
              toolBar.sizeToFit()
      
              return toolBar
          }()
      
          override var inputView: UIView? {
              return _inputView
          }
      
          override var inputAccessoryView: UIView? {
              return _inputAccessoryToolbar
          }
      
          required init?(coder aDecoder: NSCoder) {
              super.init(coder: aDecoder)
      
              let doneButton = UIBarButtonItem(title: "Done", style: UIBarButtonItem.Style.plain, target: self, action: #selector(doneClick))
              let spaceButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.flexibleSpace, target: nil, action: nil)
      
              _inputAccessoryToolbar.setItems([ spaceButton, doneButton], animated: false)
      
              let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(launchPicker))
              self.addGestureRecognizer(tapRecognizer)
          }
      
          override var canBecomeFirstResponder: Bool {
              return true
          }
      
          @objc private func launchPicker() {
              becomeFirstResponder()
          }
      
          @objc private func doneClick() {
              resignFirstResponder()
          }
      
      }
      

      【讨论】:

        【解决方案6】:

        我知道这是一个老问题,但这可能对某人仍然有用。

        还有另一种方法可以解决这个问题 - 无需使用手势识别器使事情复杂化...

        GTPDateLabel.h

        @interface GTPDateLabel : UILabel
        
        @property (readonly, retain) UIView *inputView;
        
        @end
        

        GTPDateLabel.m

        #import "GTPDateLabel.h"
        
        @implementation GTPDateLabel
        
        @synthesize inputView = _inputView;
        
        - (id)initWithFrame:(CGRect)frame
        {
            self = [super initWithFrame:frame];
        
            if (self)
            {
                self.userInteractionEnabled = YES;
            }
        
            return self;
        }
        
        - (id)initWithCoder:(NSCoder *)aDecoder
        {
            self = [super initWithCoder:aDecoder];
        
            if (self)
            {
                self.userInteractionEnabled = YES;
            }
        
            return self;
        }
        
        -(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
        {
            [super touchesEnded:touches withEvent:event];
        
            [self becomeFirstResponder];
        }
        
        - (BOOL)canBecomeFirstResponder
        {
            return YES;
        }
        
        -(UIView *)inputView
        {
            if (!_inputView)
            {
                UIDatePicker *datePicker = [[UIDatePicker alloc] init];
        
                _inputView = datePicker;
            }
        
            return _inputView;
        }
        
        @end
        

        请注意,您还应该设置delegate,如果是自定义UIPicker,还应该设置dataSource...

        【讨论】:

          【解决方案7】:

          这是在 Swift 4 中显示 PickerViewUILabel

          final class DatePickerLabel: UILabel {
            private let pickerView: UIPickerView
            private let toolbar: UIToolbar
          
            required init(pickerView: UIPickerView, toolbar: UIToolbar) {
              self.pickerView = pickerView
              self.toolbar = toolbar
              super.init(frame: .zero)
          
              let recogniser = UITapGestureRecognizer(target: self, action: #selector(tapped))
              addGestureRecognizer(recogniser)
            }
          
            required init?(coder aDecoder: NSCoder) {
              fatalError()
            }
          
            override var inputView: UIView? {
              return pickerView
            }
          
            override var inputAccessoryView: UIView? {
              return toolbar
            }
          
            override var canBecomeFirstResponder: Bool {
              return true
            }
          
            @objc private func tapped() {
              becomeFirstResponder()
            }
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2018-02-17
            • 1970-01-01
            • 1970-01-01
            • 2012-06-29
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2015-09-12
            相关资源
            最近更新 更多