Это 2017, и возможно настроить таргетинг на определенные варианты выбора. В моем проекте у меня есть таблица с классом = «варианты», а опции выбора находятся в ячейке таблицы td = «значение», а в элементе выбора есть идентификатор # pa_color. Элемент option также имеет параметр class = "attach" (среди других тегов класса). Если пользователь вошел в систему как оптовый клиент, они могут видеть все параметры цвета. Но розничным клиентам не разрешено приобретать 2 цветовых варианта, поэтому я отключил их
<option class="attached" disabled>color 1</option>
<option class="attached" disabled>color 2</option>
. Для этого потребовалась небольшая логика, но вот как я нацелился на отключенные опции выбора.
CSS
table.variations td.value select#pa_color option.attached:disabled {
display: none !important;
}
При этом мои параметры цвета видны только для оптовых покупателей.
Убедитесь, что в ваших текстовых полях установлен делегат, и реализуйте метод textFieldShouldReturn
. Этот метод вызывается, когда пользователь нажимает клавишу возврата (независимо от того, как он выглядит).
Метод может выглядеть примерно так:
func textFieldShouldReturn(textField: UITextField) -> Bool {
if textField == self.field1 {
self.field2.becomeFirstResponder()
}
return true
}
Фактическая логика здесь может отличаться. Существует множество подходов, и я бы определенно рекомендовал не использовать массивную цепочку if
/ else
, если у вас много текстовых полей, но суть здесь в том, чтобы определить, какое представление активно в данный момент, чтобы определить, каким должно быть представление. активный. Как только вы определили, какое представление должно стать активным, вызовите метод этого представления becomeFirstResponder
.
Для некоторой чистоты кода вы можете рассмотреть расширение UITextField
, которое выглядит примерно так:
private var kAssociationKeyNextField: UInt8 = 0
extension UITextField {
var nextField: UITextField? {
get {
return objc_getAssociatedObject(self, &kAssociationKeyNextField) as? UITextField
}
set(newField) {
objc_setAssociatedObject(self, &kAssociationKeyNextField, newField, .OBJC_ASSOCIATION_RETAIN)
}
}
}
А затем измените наш метод textFieldShouldReturn
, чтобы он выглядел так:
func textFieldShouldReturn(textField: UITextField) -> Bool {
textField.nextField?.becomeFirstResponder()
return true
}
Как только вы это сделаете, нужно просто установить новое свойство nextField
каждого текстового поля в viewDidLoad
:
self.field1.nextField = self.field2
self.field2.nextField = self.field3
self.field3.nextField = self.field4
self.field4.nextField = self.field1
Хотя, если мы действительно Если бы мы хотели, мы могли бы добавить префикс к свойству @IBOutlet
, и это позволило бы нам подключить наше свойство "nextField" прямо в конструкторе интерфейса.
Измените расширение так, чтобы оно выглядело следующим образом:
private var kAssociationKeyNextField: UInt8 = 0
extension UITextField {
@IBOutlet var nextField: UITextField? {
get {
return objc_getAssociatedObject(self, &kAssociationKeyNextField) as? UITextField
}
set(newField) {
objc_setAssociatedObject(self, &kAssociationKeyNextField, newField, .OBJC_ASSOCIATION_RETAIN)
}
}
}
А теперь подключите свойство nextField
в конструкторе интерфейсов:
] (Настройте своего делегата, пока вы здесь тоже.)
И, конечно, если свойство nextField
возвращает nil
, клавиатура просто скрывается.
Вот пример в Swift:
Я создал экран с 6 UITextField
с. Я назначил им теги с 1 по 6 в Интерфейсном Разработчике. Я также изменил ключ возврата на следующий в IB. Затем я реализовал следующее:
import UIKit
// Make your ViewController a UITextFieldDelegate
class ViewController: UIViewController, UITextFieldDelegate {
// Use a dictionary to define text field order 1 goes to 2, 2 goes to 3, etc.
let nextField = [1:2, 2:3, 3:4, 4:5, 5:6, 6:1]
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
// Make ourselves the delegate of the text fields so that textFieldShouldReturn
// will be called when the user hits the Next/Return key
for i in 1...6 {
if let textField = self.view.viewWithTag(i) as? UITextField {
textField.delegate = self
}
}
}
// This is called when the user hits the Next/Return key
func textFieldShouldReturn(textField: UITextField) -> Bool {
// Consult our dictionary to find the next field
if let nextTag = nextField[textField.tag] {
if let nextResponder = textField.superview?.viewWithTag(nextTag) {
// Have the next field become the first responder
nextResponder.becomeFirstResponder()
}
}
// Return false here to avoid Next/Return key doing anything
return false
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
В других ответах нет ничего плохого, это просто другой подход с преимуществом большей сосредоточенности на ООП - imho (хотя это немного сложнее, его можно использовать повторно). В раскадровке я начинаю добавлять теги с определенным диапазоном (например, 800-810), которые определяют конкретный порядок полей, между которыми я хочу перемещаться. Это дает преимущество работы со всеми подпредставлениями в главном представлении, так что можно перемещаться между UITextField и UITextView (и любым другим элементом управления) по мере необходимости.
Обычно - обычно я пытаюсь получить сообщение контроллеров представления между представлениями и объектами пользовательских обработчиков событий. Поэтому я использую сообщение (также известное как NSNotification), переданное обратно в контроллер представления из пользовательского класса делегата.
(Обработчик делегата TextField)
Примечание. В AppDelegate.swift: let defaultCenter = NSNotificationCenter.defaultCenter ()
//Globally scoped
struct MNGTextFieldEvents {
static let NextButtonTappedForTextField = "MNGTextFieldHandler.NextButtonTappedForTextField"
}
class MNGTextFieldHandler: NSObject, UITextFieldDelegate {
var fields:[UITextField]? = []
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
return true
}
func textFieldDidBeginEditing(textField: UITextField) {
textField.backgroundColor = UIColor.yellowColor()
}
func textFieldDidEndEditing(textField: UITextField) {
textField.backgroundColor = UIColor.whiteColor()
}
func textFieldShouldBeginEditing(textField: UITextField) -> Bool {
return true
}
func textFieldShouldClear(textField: UITextField) -> Bool {
return false
}
func textFieldShouldEndEditing(textField: UITextField) -> Bool {
return true
}
func textFieldShouldReturn(textField: UITextField) -> Bool {
//passes the message and the textField (with tag) calling the method
defaultCenter.postNotification(NSNotification(name: MNGTextFieldEvents.NextButtonTappedForTextField, object: textField))
return false
}
}
Это позволяет моему контроллеру представления сосредоточиться на своей основной работе по обработке сообщений между объектами, моделью и видом.
(View Controller получает сообщение от делегата и передает инструкции, используя функцию advanceToNextField)
Примечание. В моей раскадровке мои классы пользовательских обработчиков определены с использованием NSObject, и этот объект связан с Раскадровка в качестве делегата для элементов управления, которые мне нужно контролировать. Что приводит к автоматической инициализации пользовательского класса обработчика.
class MyViewController: UIViewController {
@IBOutlet weak var tagsField: UITextField! { didSet {
(tagsField.delegate as? MNGTextFieldHandler)!.fields?.append(tagsField)
}
}
@IBOutlet weak var titleField: UITextField!{ didSet {
(titleField.delegate as? MNGTextFieldHandler)!.fields?.append(titleField)
}
}
@IBOutlet weak var textView: UITextView! { didSet {
(textView.delegate as? MNGTextViewHandler)!.fields?.append(textView)
}
}
private struct Constants {
static let SelectorAdvanceToNextField = Selector("advanceToNextField:")
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
registerEventObservers()
}
override func viewDidDisappear(animated: Bool) {
super.viewDidDisappear(animated)
deRegisterEventObservers()
}
func advanceToNextField(notification:NSNotification) {
let currentTag = (notification.object as! UIView).tag
for aView in self.view.subviews {
if aView.tag == currentTag + 1 {
aView.becomeFirstResponder()
}
}
}
func registerEventObservers () {
defaultCenter.addObserver(self, selector: Constants.SelectorAdvanceToNextField, name: MNGTextFieldEvents.NextButtonTappedForTextField, object: nil)
}
func deRegisterEventObservers() {
defaultCenter.removeObserver(self, name: MNGTextFieldEvents.NextButtonTappedForTextField, object: nil)
}
....
}
Просто еще один способ добиться результата, который я нашел полезным. У моего приложения было 11 текстовых полей, за которыми следовал текстовый просмотр. Мне нужно было иметь возможность циклически проходить по всем полям, используя следующую клавишу, а затем подать в отставку клавиатуру, следуя текстовому обзору (то есть другим примечаниям).
В раскадровке я установил тэг на все поля (и текст, и текстовое представление), начиная с 1 по 12, 12 - это текстовое представление.
Я уверен, что есть и другие способы сделать это, и этот метод не идеален, но, надеюсь, он кому-нибудь поможет.
В коде я написал следующее:
func textFieldShouldReturn(textField: UITextField) -> Bool {
let nextTag = textField.tag + 1
//Handle Textview transition, Textfield programmatically
if textField.tag == 11 {
//Current tag is 11, next field is a textview
self.OtherNotes.becomeFirstResponder()
} else if nextTag > 11 {
//12 is the end, close keyboard
textField.resignFirstResponder()
} else {
//Between 1 and 11 cycle through using next button
let nextResponder = self.view.viewWithTag(nextTag) as? UITextField
nextResponder?.becomeFirstResponder()
}
return false
}
func textFieldDidEndEditing(textField: UITextField) {
textField.resignFirstResponder()
}
func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool {
//Remove keyboard when clicking Done on keyboard
if(text == "\n") {
textView.resignFirstResponder()
return false
}
return true
}