Ẩn con trỏ của UITextField


137

Tôi đang sử dụng a UITextFieldvới a UIPickerViewcho nó inputView, để khi người dùng chạm vào trường văn bản, một bộ chọn sẽ được triệu tập để họ chọn một tùy chọn từ đó.

Gần như mọi thứ đều hoạt động, nhưng tôi có một vấn đề: con trỏ vẫn nhấp nháy trong trường văn bản khi nó hoạt động, điều này xấu và không phù hợp, vì người dùng sẽ không nhập vào trường và không được trình bày bằng bàn phím. Tôi biết tôi hackily có thể giải quyết việc này bằng cách thiết lập editingđể NOvào trường văn bản và theo dõi chạm vào nó, hoặc bằng cách thay thế nó bằng một nút tùy chỉnh theo kiểu, và triệu tập các bảng chọn thông qua mã. Tuy nhiên, tôi muốn sử dụng các UITextFieldDelegatephương thức cho tất cả các xử lý sự kiện trên trường văn bản và các bản hack như thay thế trường văn bản bằng một nút không cho phép phương pháp này.

Làm thế nào tôi có thể đơn giản ẩn con trỏ trên UITextFieldthay thế?

Câu trả lời:


277

Đơn giản chỉ cần phân lớp UITextField và ghi đè caretRectForPocation

- (CGRect)caretRectForPosition:(UITextPosition *)position
{
    return CGRectZero;
}

2
Xinh đẹp! Hoạt động như một cơ duyên đối với tôi.
Joe Strout

1
@Joseph Chiu Nó hoạt động rất tốt. Nhưng không phải với iOS 4.3. Ông có thể giúp tôi với điều này?
Dinesh Raja

cách tiếp cận sạch nhất và ngắn nhất xứng đáng nhận được gấp đôi =)
Ilker Baltaci

1
Chỉ cần một lưu ý. Trong lớp con của tôi, tôi đã thêm một bool hideCaret sau đó trong phần ghi đè này Nếu nó đúng -> trả về CGRectZero khác trả về kết quả của super.
WCByrne

6
Chỉ cần lưu ý rằng người dùng có bàn phím ngoài có thể thay đổi giá trị của trường văn bản ngay cả khi con trỏ bị ẩn và bạn sử dụng chế độ xem bộ chọn.
Đánh dấu

156

Kể từ iOS 7, bạn có thể chỉ cần đặt tintColor = [UIColor clearColor]textField và dấu mũ sẽ biến mất.


1
Điều này hoạt động vào lúc này, tuy nhiên tôi sẽ khuyên bạn không nên sử dụng nó vì nó có thể thay đổi trong tương lai. Thay vì lựa chọn cho caretRectForPosition:giải pháp ghi đè.
lipka

@lipka Đúng, đó có lẽ là một cách tốt hơn.
jamone

2
Đủ tốt cho bây giờ Đôi khi bạn chỉ cần một giải pháp nhanh chóng.
GoldenJoe

Đây là giải pháp dễ nhất cho đến nay!
Jay Q.

1
Câu trả lời này phải được chấp thuận cho iOS 7+
thử

95

Bạn chỉ có thể xóa tintColor của trường văn bản

self.textField.tintColor = [UIColor clearColor];

Swift 3.0

self.textField.tintColor = .clear

nhập mô tả hình ảnh ở đây


Câu trả lời dễ nhất
Nik Kov

2
Như đã đề cập ở trên, việc xóa màu sắc không ngăn người dùng bằng bàn phím ngoài (iPad Pro) thay đổi văn bản.
Michael Long

@MichaelLong đây không phải là về việc ngăn người dùng thay đổi văn bản, đây chỉ là một lựa chọn kiểu dáng.
JRam13

21

Bạn cũng có thể muốn ngăn người dùng chọn, sao chép hoặc dán bất kỳ văn bản nào để đầu vào văn bản duy nhất đến từ chế độ xem bộ chọn.

- (CGRect) caretRectForPosition:(UITextPosition*) position
{
    return CGRectZero;
}

- (NSArray *)selectionRectsForRange:(UITextRange *)range
{
    return nil;
}

- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
    if (action == @selector(copy:) || action == @selector(selectAll:) || action == @selector(paste:))
    {
        returnNO;
    }

    return [super canPerformAction:action withSender:sender];
}

http://b2cloud.com.au/tutorial/diseac-the-caret-and-text-entry-in-uitextfields/


15

Kiểm tra thuộc tính selectedTextRange của giao thức UITextInputlớp UITextField phù hợp. Vài! Đó là một bài học về lập trình hướng đối tượng ngay tại đó.

Ẩn Caret

Để ẩn dấu mũ, hãy điền vào phạm vi văn bản đã chọn của trường văn bản.

textField.selectedTextRange = nil; // hides caret

Không quan tâm

Dưới đây là hai cách để bỏ dấu mũ.

  1. Đặt phạm vi văn bản đã chọn của trường văn bản ở cuối tài liệu.

    UITextPosition *end = textField.endOfDocument;
    textField.selectedTextRange = [textField textRangeFromPosition:end
                                                        toPosition:end];
  2. Để giữ dấu mũ ở cùng một vị trí, trước tiên, hãy lưu trữ phạm vi văn bản đã chọn của trường văn bản vào một biến thể hiện.

    _textFieldSelectedTextRange = textField.selectedTextRange;
    textField.selectedTextRange = nil; // hides caret

    Sau đó, khi bạn muốn bỏ ẩn dấu mũ, chỉ cần đặt phạm vi văn bản đã chọn của trường văn bản trở lại như ban đầu:

    textField.selectedTextRange     = _textFieldSelectedTextRange;
    _textFieldLastSelectedTextRange = nil;

3
Giải pháp đặc biệt này đã không làm việc cho việc thực hiện của tôi. Con trỏ vẫn nhấp nháy.
Art Geigel

Chà, có lẽ, bạn nên gửi một lỗi tại bugreport.apple.com vì các tài liệu iOS nói: "Nếu phạm vi văn bản có độ dài, nó chỉ ra văn bản hiện được chọn. Nếu nó có độ dài bằng không, nó chỉ ra dấu mũ (chèn điểm). Nếu đối tượng phạm vi văn bản là 0, nó chỉ ra rằng không có lựa chọn hiện tại nào. "
ma11hew28

4
Tôi không quan tâm đủ để nộp báo cáo. Nếu người khác sử dụng "giải pháp" của bạn và không thấy nó hoạt động, tôi muốn họ biết rằng họ không đơn độc.
Art Geigel

Bất chấp ý kiến ​​của @ ArtGeigel, điều này hoạt động hoàn hảo với tôi. Tuy nhiên, tôi loại giải pháp liên quan đến ghi đè caretRectForPosition. Nó rõ ràng hơn những gì nó đang làm, và các tài liệu mà bạn đã trích dẫn không làm rõ hành vi của dấu mũ sẽ là gì khi không có 'lựa chọn hiện tại'. Nếu @ ArtGeigel tuyên bố rằng điều này không hoạt động là chính xác (điều đó không phải, ít nhất là theo như tôi có thể thấy) thì rõ ràng đó không phải là một lỗi.
Đánh dấu Amery

Tôi cũng không làm việc. Caret vẫn ở đó và chớp mắt.
CW0007007

11

Câu trả lời được cung cấp bởi OP, được sao chép từ cơ quan câu hỏi để giúp dọn sạch phần đuôi của những câu hỏi chưa được trả lời.

Tôi tìm thấy một giải pháp khác: lớp con UIButtonvà ghi đè các phương thức này

- (UIView *)inputView {
    return inputView_;
}

- (void)setInputView:(UIView *)anInputView {
    if (inputView_ != anInputView) {
        [inputView_ release];
        inputView_ = [anInputView retain];
    }
}

- (BOOL)canBecomeFirstResponder {
    return YES;
}

Bây giờ, nút, như một UIResponder, có một hành vi tương tự UITextFieldvà thực hiện khá đơn giản.


5
Đây không thực sự là một giải pháp tuyệt vời. Kiểm tra câu trả lời dưới đây: stackoverflow.com/a/13660503/1103584
DiscDev

2
Tại sao đây không phải là một giải pháp tuyệt vời? Nó đạt được hiệu quả mong muốn và cũng cung cấp chức năng cho một lớp mà trước đây không có nó. Nó cũng không phải là một hack. Tôi nghĩ nó thật tuyệt Vậy có chuyện gì với nó vậy?
BreadicalMD

2
@BreadicalMD Vấn đề lớn nhất tôi có thể thấy là bạn không thể sử dụng cái UITextFieldDelegatenày để xử lý các sự kiện chỉnh sửa bắt đầu và kết thúc. Thay vào đó - trừ khi có cách xử lý các sự kiện mà tôi không biết - bạn sẽ cần ghi đè becomeFirstResponderresignFirstRespondertrong lớp con nút và có thể tạo giao thức đại biểu của riêng bạn, thêm vào một thuộc delegatetính và gọi cho đại biểu từ đã nói ở trên phương pháp. Đây là tất cả công việc nhiều hơn nhiều so với chỉ ghi đè caretRectForPositiontrong một UITextFieldlớp con.
Đánh dấu Amery

1
@BreadicalMD Điều đó nói rằng, mặc dù câu trả lời của Joseph Chiu vượt trội hơn bất kỳ quan điểm thực tế nào, tôi vẫn đồng ý với bạn rằng điều này khá gợi cảm. Tôi chưa bao giờ nhìn kỹ vào UIRespondertài liệu tham khảo lớp trước đây, và không biết rằng một mẹo như thế này là có thể.
Đánh dấu Amery

Đến bữa tiệc muộn, nhưng tôi nghĩ đây là một giải pháp rất tốt và nó cảm thấy phù hợp và ít bị hack hơn là sử dụng UITextFieldvà ẩn con trỏ, về cơ bản là hack vì chúng tôi đang sử dụng trường văn bản làm nhãn trong khi không sử dụng bất kỳ chức năng nào của UITextField.
Rupert

7

Swift 5 phiên bản bài đăng của Net

  override func caretRect(for position: UITextPosition) -> CGRect {
    return .zero
  }
  
  override func selectionRects(for range: UITextRange) -> [UITextSelectionRect] {
    return []
  }
  
  override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
    return false
  }

Trong trường hợp của tôi, nó đã làm việc. Đã thêm một lớp con của UITextField với các phương thức này bằng Swift 4. Cảm ơn!
J. Fdez

3

Đặt tintColor thành Xóa màu

textfield.tintColor = [UIColor clearColor];

và bạn cũng có thể thiết lập từ trình xây dựng giao diện


2
Bạn vừa sao chép một câu trả lời từ hơn 2 năm trước.
Ashley Mills

1
xin lỗi bạn tôi, nhưng tôi không sao chép gì cả
Ahmad Al-Attal

4
Thật thú vị, "bạn của tôi". Câu trả lời của bạn trông khá gần với câu trả lời của @ oldman từ ngày 1 tháng 5 năm15. Bạn có thể cho tôi biết làm thế nào là khác nhau của bạn?
Ashley Mills

1
Như đã đề cập ở trên, việc xóa màu sắc không ngăn người dùng bằng bàn phím ngoài (iPad Pro) thay đổi văn bản.
Michael Long

Người dùng chuyên nghiệp có thể làm những gì họ muốn. Họ là ưu điểm: họ biết những gì họ đang làm; ^)
Anton Tropashko

2

Nếu bạn muốn ẩn con trỏ, bạn có thể dễ dàng sử dụng điều này! Nó làm việc cho tôi ..

[[textField valueForKey:@"textInputTraits"] setValue:[UIColor clearColor] forKey:@"insertionPointColor"]

3
Điều này là không có giấy tờ, theo như tôi biết. Có thể việc sử dụng điều này sẽ khiến ứng dụng của bạn bị từ chối vì gọi API riêng nếu bạn gửi nó tới cửa hàng ứng dụng, mặc dù tôi không biết bất kỳ bài nộp nào sử dụng điều này để kiểm tra suy đoán này bằng cách này hay cách khác. Thật đáng tiếc, vì thật tuyệt khi có thể giải quyết vấn đề này mà không cần phân lớp và câu trả lời này cho phép điều đó.
Đánh dấu Amery

1

Câu trả lời được cung cấp bởi OP, được sao chép từ cơ quan câu hỏi để giúp dọn sạch phần đuôi của những câu hỏi chưa được trả lời.

Tôi nghĩ rằng tôi có giải pháp chính xác nhưng nếu nó có thể được cải thiện sẽ được chào đón :) Vâng, tôi đã tạo một lớp con của UITextField và ghi đè lên phương thức trả về CGRect cho giới hạn

-(CGRect)textRectForBounds:(CGRect)bounds {
    return CGRectZero;
}

Vấn đề? Các văn bản không hiển thị vì trực tràng bằng không. Nhưng tôi đã thêm một UILabel dưới dạng một khung nhìn phụ của điều khiển và ghi đè phương thức setText, vì vậy, khi chúng ta nhập một văn bản như bình thường, văn bản trường văn bản là không và là nhãn hiển thị văn bản

- (void)setText:(NSString *)aText {
    [super setText:nil];

    if (aText == nil) {
        textLabel_.text = nil;
    }

    if (![aText isEqualToString:@""]) {
        textLabel_.text = aText;
    }
}

Với điều này hoạt động như mong đợi. Bạn có biết cách nào để cải thiện nó?


Câu trả lời này về cơ bản là vô giá trị khi cho rằng phương pháp thay thế của Joseph Chiu rất giống nhưng đơn giản hơn nhiều. Tôi có thể đề nghị chỉ cần xóa nó?
Đánh dấu Amery

1

Để tắt cả con trỏ và menu tôi sử dụng lớp con với 2 phương thức sau:

- (CGRect)caretRectForPosition:(UITextPosition *)position {
    return CGRectZero;
}

- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
    [UIMenuController sharedMenuController].menuVisible = NO;
    self.selectedTextRange = nil;

    return NO;
}

0

Tôi chỉ đơn giản là phân lớp UITextFieldvà ghi đè layoutSubviewsnhư sau:

- (void)layoutSubviews
{
    [super layoutSubviews];
    for (UIView *v in self.subviews)
    {
        if ([[[v class] description] rangeOfString:@"UITextSelectionView"].location != NSNotFound)
        {
            v.hidden = YES;
        }
    }
}

Đó là một bản hack bẩn và có thể thất bại trong tương lai (tại thời điểm đó, con trỏ sẽ hiển thị lại - ứng dụng của bạn sẽ không gặp sự cố), nhưng nó hoạt động.


-1

Bạn có thể thêm một thuộc BOOL cursorlesstính UITextFieldvào một danh mục thông qua các đối tượng liên quan.

@interface UITextField (Cursorless)

@property (nonatomic, assign) BOOL cursorless;

@end

Sau đó, sử dụng phương pháp swizzling để swizzle caretRectForPosition:với một phương thức chuyển đổi giữa CGRectZerovà giá trị mặc định của nó bằng cách sử dụng cursorless.

Điều này dẫn đến một giao diện đơn giản thông qua danh mục thả vào. Điều này được thể hiện trong các tập tin sau.

Chỉ cần thả chúng vào và nhận được lợi ích của giao diện đơn giản này

UITextFielddanh mục: https://github.com/rexmas/RexDK/blob/master/RexDK/UI/UITextField%2BRXCoderless.h https://github.com/rexmas/RexDK/blob/master/RexDK/UI/UITextField%2X .m

Phương pháp Swizzling: https://github.com/rexmas/RexDK/blob/master/RexDK/Foundation/NSObject%2BRXR.78Additions.h https://github.com/rexmas/RexDK/blob/master/RexDK/Foundation 2BRXR.78Additions.m


một giải pháp xấu về SO nhiều cấp độ! cho người mới bắt đầu: Không bao giờ ghi đè các phương thức trong danh mục. Tránh phương pháp Swizziling trừ khi bạn thực sự, thực sự cần nó (người khác đã đưa ra giải pháp tốt cho câu hỏi này). Nó làm cho mã của bạn phức tạp hơn nhiều.
EsbenB

Nếu bạn thực sự nhìn vào mã, bạn sẽ nhận ra rằng không có phương thức nào bị ghi đè trong danh mục và phương thức thay đổi được thực hiện chính xác. Tôi đã sử dụng triển khai này trong nhiều năm mà không thất bại.
Tuyệt vời-o

Ngoài ra, giải thích những gì phức tạp về việc thêm một cơ sở mã bị cô lập ~ 150 dòng để giải quyết vĩnh viễn một vấn đề tái diễn liên tục? Điều này không chỉ KHÔNG làm phức tạp cơ sở mã của bạn mà còn cung cấp giao diện đơn giản nhất có thể; một boolean duy nhất để ra lệnh các chức năng.
Tuyệt vời-o

hãy xem cuộc thảo luận tuyệt vời này về phương pháp stackoverflow swizzling.com/questions/5339276/ chủ yếu là về gỡ lỗi. Phương pháp swizzling là một tính năng tuyệt vời, nhưng IMHO chỉ nên được sử dụng khi cần thiết. Vấn đề này rất dễ giải quyết bằng một trong những gợi ý được cung cấp ở đây và sẽ cung cấp mã dễ dàng hơn để duy trì và đọc cho các lập trình viên khác.
EsbenB

Tôi đã đọc điều đó trước đây và tôi đã làm theo tất cả các hướng dẫn được phác thảo trong quá trình thực hiện của mình cho chính xác. Có thể cho rằng, đây là một ví dụ chắc chắn khi phương pháp swizzling thắng. Tuy nhiên, đây là một trường hợp phổ biến, trong đó các thư viện cơ bản không triển khai một tính năng cần thiết rộng rãi trên các nền tảng một cách đơn giản. Các ví dụ khác được đề xuất không xác định về mặt ngữ nghĩa một trường văn bản không có con trỏ, họ chỉ thực hiện nó thông qua việc che giấu khung của con trỏ hoặc màu của nó. Đối với một lập trình viên mới, giao diện này là dễ đọc nhất và thực hiện chính xác những gì được mong đợi từ nó.
Tuyệt vời-o
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.