Сховати курсор поля UITextField


137

Я використовую a UITextFieldз UIPickerViewдля його inputView, так що коли користувач натискає текстове поле, викликається вибирач, щоб вибрати варіант.

Майже все працює, але у мене є одна проблема: курсор все ще блимає в текстовому полі, коли він активний, що некрасиво і недоцільно, оскільки користувач не очікує введення в поле і не має клавіатури. Я знаю , що я міг би hackily вирішити цю проблему, встановивши editingв NOна текстовому полі і відстеження штрихів на нього, або, замінивши його на замовлення в стилі кнопки і виклику збирача з допомогою коду. Однак я хочу використовувати UITextFieldDelegateметоди для всіх подій в текстовому полі, а хаки, такі як заміна текстового поля кнопкою, не дозволяють такий підхід.

Як я можу просто заховати курсор UITextFieldнатомість?

Відповіді:


277

Просто підклас UITextField і замініть caretRectForPosition

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

2
Гарний! Працює як шарм для мене.
Джо Строут

1
@Joseph Chiu Це чудово працює. Але не з iOS 4.3. Чи можете ви мені в цьому допомогти?
Дінеш Раджа

найчистіший і найкоротший підхід, який заслуговує подвійного оновлення =)
Ілкер Балтачі

1
Просто записка. У свій підклас я додав bool hidCaret, тоді в цьому переосмисленні Якщо це правда -> повернути CGRectZero, ще повернути результат супер.
WCByrne

6
Зауважте, що користувачі із зовнішньою клавіатурою можуть змінювати значення текстового поля, навіть якщо курсор прихований і ви використовуєте подання вибору.
Марк

156

Станом на iOS 7 тепер ви можете просто встановити tintColor = [UIColor clearColor]на textField і карета зникне.


1
Це працює на даний момент, проте я б радив не використовувати його, оскільки це може змінитися в майбутньому. Швидше caretRectForPosition:вибирайте рішення, що переосмислює.
lipka

@lipka Щоправда, це, мабуть, кращий спосіб.
jamone

2
Наразі досить добре. Іноді просто потрібно швидке рішення.
GoldenJoe

Це найпростіше рішення на сьогоднішній день!
Джей Q.

1
Цю відповідь слід затвердити для iOS 7+
tryp

95

Ви можете просто очистити відтінок кольорового поля тексту

self.textField.tintColor = [UIColor clearColor];

Swift 3.0

self.textField.tintColor = .clear

введіть тут опис зображення


Найпростіша відповідь.
Нік Ков

2
Як було сказано вище, очищення кольору відтінку не перешкоджає користувачам із зовнішніми клавіатурами (iPad Pro) змінювати текст.
Майкл Лонг

@MichaelLong це не про те, щоб не зупинити користувача на зміні тексту, це лише вибір стилю.
JRam13

21

Ви також можете зупинити користувач у виборі, копіюванні чи вставці будь-якого тексту, щоб єдине введення тексту надходило з подання вибору.

- (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/disabling-the-caret-and-text-entry-in-uitextfields/


15

Перевірте властивість selectedTextRange цього протоколу UITextInput , до якого клас UITextField відповідає встановленим вимогам. Мало! Це урок об’єктно-орієнтованого програмування саме там.

Сховати каре

Щоб приховати карету, ліквідуйте вибраний діапазон тексту.

textField.selectedTextRange = nil; // hides caret

Відкрити карет

Ось два способи розкрити каре.

  1. Встановіть вибраний діапазон тексту в кінці документа.

    UITextPosition *end = textField.endOfDocument;
    textField.selectedTextRange = [textField textRangeFromPosition:end
                                                        toPosition:end];
  2. Щоб зберегти карету на тому самому місці, спочатку збережіть вибраний діапазон тексту у змінній екземпляра.

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

    Потім, коли ви хочете приховати карету, просто встановіть вибраний діапазон тексту назад у тому, яким він був раніше:

    textField.selectedTextRange     = _textFieldSelectedTextRange;
    _textFieldLastSelectedTextRange = nil;

3
Це конкретне рішення не працювало для моєї реалізації. Курсор все ще блимає.
Art Geigel

Ну, то, можливо, вам слід подати помилку на bugreport.apple.com, оскільки документи в iOS кажуть: "Якщо діапазон тексту має довжину, він вказує на вибраний на даний момент текст. Якщо він має нульову довжину, він вказує на каре (вставка точка). Якщо об'єкт діапазону тексту є нульовим, це вказує на відсутність поточного вибору. "
ma11hew28

4
Мені не все одно, щоб подати звіт. Якщо інші використовують ваше "рішення" і не бачать, що це працює, я хотів, щоб вони знали, що вони не самотні.
Art Geigel

Незважаючи на коментарі @ ArtGeigel, це прекрасно працює для мене. Однак я наче віддаю перевагу рішенню, яке передбачає переоцінку caretRectForPosition. Це більш чітко, що він робить, і документи, які ви цитували, не пояснюють, якою має бути поведінка карети, коли "немає поточного вибору". Якби твердження @ ArtGeigel про те, що це не працює, було правильним (що це не так, принаймні, наскільки я бачу), не було б зрозуміло, що це помилка.
Марк Амері

Не працював і для мене. Карет все ще є і моргає.
CW0007007

11

Відповідь, надана ОП, скопійована з органу запитань, щоб допомогти очистити постійно зростаючий хвіст питань без відповідей.

Я знайшов інше рішення: підклас UIButtonта переосмислення цих методів

- (UIView *)inputView {
    return inputView_;
}

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

- (BOOL)canBecomeFirstResponder {
    return YES;
}

Тепер кнопки, як UIResponder, мають схожу поведінку, ніж UITextFieldта реалізація досить прості.


5
Це насправді не чудове рішення. Перевірте цей відповідь нижче: stackoverflow.com/a/13660503/1103584
DiscDev

2
Чому це не чудове рішення? Він досягає наміченого ефекту, а також забезпечує функціональність для класу, у якого раніше його не було. Це також не хак. Я думаю, це дійсно круто. То що з цим погано?
BreadicalMD

2
@BreadicalMD Найбільша проблема, яку я бачу, полягає в тому, що ви не можете використовувати a UITextFieldDelegateдля цього, щоб обробляти події редагування і закінчення. Натомість - якщо не існує способу поводження з тими подіями, про які я не знаю - вам потрібно буде переозначити becomeFirstResponderі resignFirstResponderв підкласі кнопок і, можливо, створити власний протокол делегата, додати delegateвластивість та викликати делегата із вищезгаданого методи. Це все набагато більше роботи , ніж просто перевизначення caretRectForPositionв UITextFieldпідкласі.
Марк Амері

1
@BreadicalMD Тим не менш, незважаючи на те, що відповідь Джозефа Чіу перевершує будь-яку практичну точку зору, я все одно погоджуюся з вами, що це досить сексуально. Я ніколи раніше уважно не дивився на UIResponderпосилання на клас і не здогадувався, що така хитрість можлива.
Марк Амері

Пізно до партії, але я вважаю, що це дуже хороше рішення, і це відчуває себе набагато доречніше і менше хак, ніж використання UITextFieldта приховування курсору, що в основному є хаком, оскільки тоді ми використовуємо текстове поле як мітку, не використовуючи жодної функціональності UITextField.
Руперт

7

Swift 5 версія публікації 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
  }

У моєму випадку це спрацювало. Додано підклас UITextField за допомогою цих методів за допомогою Swift 4. Дякую!
Дж. Фдез

3

встановіть для tintColor значення Clear Color

textfield.tintColor = [UIColor clearColor];

і ви також можете встановити програму інтерфейсу


2
Ви щойно скопіювали відповідь понад 2 роки тому.
Ешлі Міллс

1
вибач, мій друг, але я нічого не копіював.
Ахмад Аль-Аттал

4
Це цікаво, "мій друже". Ваша відповідь виглядає досить близькою до відповіді @ oldman від 1 травня 15 року. Чи можете ви сказати мені, як ваш відрізняється?
Ешлі Міллс

1
Як було сказано вище, очищення кольору відтінку не перешкоджає користувачам із зовнішніми клавіатурами (iPad Pro) змінювати текст.
Майкл Лонг

Професійні користувачі можуть робити все, що їм заманеться. Вони плюси: вони знають, що роблять; ^)
Антон Тропашко

2

Якщо ви хочете приховати курсор, ви можете легко скористатися цим! Це працювало для мене ..

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

3
Наскільки я знаю, це недокументовано. Можливо, що за допомогою цієї програми ваш додаток буде відхилено для виклику приватних API, якщо ви надішліть його в магазин додатків, хоча я не знаю жодних матеріалів, які використовують це для перевірки тієї чи іншої міркування. Шкода, адже було б непогано мати можливість вирішити цю проблему без підкласу, і ця відповідь дозволяє це.
Марк Амері

1

Відповідь, надана ОП, скопійована з органу запитань, щоб допомогти очистити постійно зростаючий хвіст питань без відповідей.

Я думаю, що у мене є правильне рішення, але якщо його можна вдосконалити, буде вітатися :) Добре, я створив підклас UITextField і замінив метод, який повертає CGRect для меж

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

Проблема? Текст не відображається, оскільки прямокутне значення дорівнює нулю. Але я додав UILabel як підперегляд контролю та замінив метод setText, так що, як ми вводимо текст як завжди, текст поля тексту є нульовим і є міткою, що показує текст

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

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

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

При цьому річ працює так, як очікувалося. Чи знаєте ви який-небудь спосіб її покращити?


Ця відповідь в принципі нікчемна, враховуючи, що альтернативний підхід Джозефа Чіу дуже схожий, але набагато простіший. Можна запропонувати просто видалити його?
Марк Амері

1

Для відключення курсору та меню я використовую підклас із цими двома методами:

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

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

    return NO;
}

0

Я просто підклас UITextFieldі переосмислюю layoutSubviewsнаступним чином:

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

Це брудне злом, і може в майбутньому вийти з ладу (після цього курсор знову буде видно - ваш додаток не вийде з ладу), але він працює.


-1

Ви можете додати BOOL cursorlessвластивість до UITextFieldкатегорії за допомогою пов’язаних об’єктів.

@interface UITextField (Cursorless)

@property (nonatomic, assign) BOOL cursorless;

@end

Потім використовуйте метод swizzling для swizzle caretRectForPosition:з методом, який перемикається на значення CGRectZeroта його значення за замовчуванням, використовуючиcursorless .

Це призводить до простого інтерфейсу через категорію, що випадає. Це показано в наступних файлах.

Просто занесіть їх і скористайтеся цим простим інтерфейсом

UITextFieldкатегорія: https://github.com/rexmas/RexDK/blob/master/RexDK/UI/UITextField%2BRXCursorless.h https://github.com/rexmas/RexDK/blob/master/RexDK/UI/UITextField%2BRXCursorless .m

Метод Swizzling: https://github.com/rexmas/RexDK/blob/master/RexDK/Foundation/NSObject%2BRXRuntimeAdditions.h https://github.com/rexmas/RexDK/blob/master/RexDK/Foundation/NSObject% 2BRXRuntimeAdditions.m


погане рішення на ТАКІХ рівнях! для початківців: Ніколи не перекривайте методи в категоріях. Уникайте методу Swizziling, якщо вам це справді дуже не потрібно (інші придумали хороші рішення цього питання). Це робить ваш код набагато складнішим.
EsbenB

Якщо ви насправді подивилися на код, то зрозуміли б, що жоден метод не перекрито в категорії, а метод шипування реалізований правильно. Я використовую цю реалізацію протягом багатьох років безвідмовно.
Awesome-o

Також поясніть, що складне в додаванні ізольованої бази коду ~ 150 рядків для постійного вирішення постійно повторюваної проблеми? Це не тільки не ускладнить вашу кодову базу, але й надасть найпростіший можливий інтерфейс; єдиний булевий, щоб продиктувати функціональність.
Awesome-o

подивіться на цю прекрасну дискусію про метод swizzling stackoverflow.com/questions/5339276 / ... Особливо на налагодження. Швидкісні способи є дивовижною особливістю, але IMHO слід застосовувати лише за потреби. Цю проблему легко вирішити, скориставшись однією з запропонованих тут пропозицій, та надасть код простішим у обслуговуванні та читанні для інших програмістів.
EsbenB

Я читав це раніше, і я дотримувався всіх викладених вказівок у своїй реалізації для коректності. Можливо, це вагомий приклад того, коли виграє метод свистування. Це відокремлений, але поширений випадок, коли базові бібліотеки не в змозі просто реалізувати необхідну функцію на платформах. Інші запропоновані приклади не мають семантичного визначення текстового поля без курсору, вони виконують його лише через притуплення або кадру курсору, або його кольору. Новому програмісту цей інтерфейс найпростіше читати і робить саме те, що від нього очікується.
Awesome-o
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.