Предотвратить UIStepper от 0?

У меня есть UIStepper, у которого есть stepValue из 1. Я хотел бы, чтобы UIStepper мог быть положительным или отрицательным до его значений maximum и minimum, но никогда 0.

Каждая попытка, которую я предпринял для решения этой проблемы, не может объяснить, уменьшался или увеличивался степпер (таким образом, следует пропустить 0 до 1 или до -1). Единственное, что я могу придумать, это сохранить предыдущее значение и сравнить его, но это звучит немного сложно для такой простой задачи.

Любые идеи? Кто-нибудь еще сталкивался с такими же требованиями?


person Community    schedule 03.07.2019    source источник
comment
каковы были ваши попытки?   -  person Lu_    schedule 03.07.2019
comment
В valueChanged определите, равен ли он 0, и жестко закодируйте либо 1, либо -1. Но, как я объяснил, я не мог понять, как определить, когда что делать.   -  person    schedule 03.07.2019
comment
Поскольку значение равно нулю, определить, был ли шаг положительным или отрицательным, невозможно без дополнительной информации. Вы не знаете, в каком состоянии был степпер ранее, если не запишете его. Так что все не так просто, как кажется :)   -  person JonJ    schedule 03.07.2019
comment
@JonJ Я записываю это ... но устанавливая переменную в значение шагового двигателя в вызовах valueChanged.   -  person    schedule 03.07.2019


Ответы (2)


Я бы подошел к этому с другой стороны. Позвольте степперу делать то, что он делает, и просто измените его интерпретацию.

Например, если у вас есть степпер, который вы хотите перейти от -5 к +5, но пропуская 0:

  1. Установите степпер minumum на -5.
  2. Установите степпер maximum на 4.
  3. Установите степпер stepValue на 1.
  4. Когда вы читаете степпер value, добавьте 1, если value неотрицательно:

    let value = stepper.value + (stepper.value < 0 ? 0 : 1)
    
  5. Когда вы устанавливаете степпер value, сначала уменьшите положительные значения на 1:

    // value of 3 will be represented in the stepper by 2
    value = 3
    stepper.value = value - (value > 0 ? 1 : 0)
    

Скройте детали с помощью nonZeroValue вычисляемого свойства

Вы можете скрыть эти корректировки +1 и -1, создав расширение для UIStepper, которое добавляет новое вычисляемое свойство с именем nonZeroValue.

extension UIStepper {
    var nonZeroValue: Double {
        get {
            return self.value + (self.value < 0 ? 0 : 1)
        }
        set {
            self.value = newValue - (newValue < 0 ? 0 : 1)
        }
    }
}

Затем просто используйте stepper.nonZeroValue вместо stepper.value в своем коде.

person vacawama    schedule 03.07.2019
comment
Разве это не изменится, если кнопки шагового увеличения/уменьшения станут серыми, если вообще изменятся? (Еще не пробовал.) Я читаю значение в valueChanged и отображаю в метке. - person ; 03.07.2019
comment
Попытайся. Он будет делать то, что вы хотите. Подумайте о шаговом значении как о внутренней детали реализации, которую необходимо сопоставить с тем, что вы перешагиваете. Снижая максимум на 1, теперь у вас есть степпер, который может перешагнуть нужное количество значений, вам просто нужно интерпретировать неотрицательные значения как одно большее, чем внутреннее значение степпера. - person vacawama; 03.07.2019
comment
Когда вы читаете значение в valueChanged, просто выполните вычисление, показанное на шаге 4, перед отображением в метке. - person vacawama; 03.07.2019
comment
Степпер не уменьшает, а каждый раз добавляет +2. - person ; 03.07.2019
comment
Это то, что я пробовал также. По-прежнему добавляет +2 к приращению и уменьшается только при нажатии и удержании. - person ; 03.07.2019
comment
У вас все еще должен быть код, который искажает значение при его изменении (возможно, из другого ответа). Шаговый двигатель должен свободно изменять свои значения. - person vacawama; 03.07.2019
comment
Неа. Вызываемый метод — это буквально ваш код, который затем обновляет метку. - person ; 03.07.2019
comment
Если только... какое значение шагового двигателя должно быть установлено в cellForRow? В настоящее время он установлен на контракты (или глобальную переменную для количества). - person ; 03.07.2019
comment
Если значение по умолчанию равно 1, максимальное значение равно 100 (установлено на 99), а минимальное значение равно -100. - person ; 03.07.2019
comment
Если вы set значение шагового двигателя, вам нужно сделать обратное сопоставление. Вычтите 1 перед установкой значения, если › 0. - person vacawama; 03.07.2019

Это довольно просто с наблюдением за ключом и значением. Требуется IBOutlet шагового двигателя

@IBOutlet var stepper: UIStepper!

Объявите свойство NSKeyValueObservation

var observation : NSKeyValueObservation?

В viewDidLoad наблюдайте за value шагового двигателя и настройте его, если новое значение равно 0. Преимущество KVO заключается в том, что вы получаете значения old и new для определения направления шага.

override func viewDidLoad() {
    super.viewDidLoad()
    observation = stepper.observe(\.value, options: [.old, .new], changeHandler: { (stepper, change) in
        if change.newValue! == 0.0 {
            if change.newValue! > change.oldValue! {
                stepper.value = 1
            } else {
                stepper.value = -1
            }
        } 
    })
}

Если степпер находится в ячейке табличного представления, объявите розетку и свойство observation в ячейке и назначьте наблюдателя в cellForRow контроллера.

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! MyGreatCell
    let model = datasource[indexPath.row] // just an example
    cell.stepper.value = model.stepperValue
    ... 
    cell.observation = cell.observe(\.stepper.value, options: [.old, .new], changeHandler: { (stepper, change) in
        if change.newValue! == 0.0 {
            if change.newValue! > change.oldValue! {
                stepper.value = 1
            } else {
                stepper.value = -1
            }
        }
        model.stepperValue = stepper.value
    } 
    return cell
 }

И вам нужно реализовать didEndDisplaying, чтобы освободить наблюдателя

func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    let tableCell = cell as! MyGreatCell
    tableCell.observation = nil
}
person vadian    schedule 03.07.2019
comment
Хм... кажется, у меня не работает. Если это поможет, UIStepper находится в ячейке табличного представления. Я также попробовал код в viewDidAppear на тот случай, если ячейка должна быть выложена, прежде чем она сможет работать. Кроме того, вернет ли это скорректированное значение для вызова valueChanged? - person ; 03.07.2019
comment
Я обновил ответ. Вы должны установить текущее значение шагового двигателя и обновить модель в замыкании observation в cellForRow. IBAction вместо valueChanged не требуется. - person vadian; 03.07.2019
comment
Нужно ли мне подклассифицировать мою ячейку (в настоящее время нет)? Есть ли способ сделать это без создания подкласса ячейки и предотвращения утечек памяти? Спасибо. - person ; 03.07.2019
comment
Да, вам нужно создать подкласс ячейки. Пользовательские ячейки представления таблицы по умолчанию не вызывают утечек памяти, если вы не написали уродливый код. - person vadian; 03.07.2019