Программно сгенерированные UIB-кнопки не реагируют - PullRequest
0 голосов
/ 31 декабря 2018

Я генерирую UIButtons динамически и помещаю их в динамически измеряемый UIImageView.Я создал кнопки в цикле, затем в другом цикле я установил их ограничения на основе доступного пространства.Все работает, то есть кнопки и их текст отображаются красиво отсортированными, НО при нажатии на них ничего не происходит.button.isUserinteractionIsEnables = YES.

При входе кнопок в последний цикл I они не имеют координат Y, X.Я думаю, что мои якоря должны позаботиться об этом.Или объединение CGRect с якорями - всегда плохая идея?

EDIT: исправлено При инициализации родительского класса кнопки мне пришлось установить .isUserInteractionEnabled = true;Если в какой-то момент у представления отключено взаимодействие с пользователем, то оно откажется выполнять свое стандартное действие, которое включает в себя не передачу события ни в одно из его подпредставлений

import UIKit

class SuggenstionCloud: UIImageView {

    override init(image: UIImage?) {
        super.init(image: image)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    public func setConstraints(
        topAnchor : NSLayoutAnchor<NSLayoutYAxisAnchor>, topConstant: CGFloat,
        bottomAnchor: NSLayoutAnchor<NSLayoutYAxisAnchor>, bottomConstant: CGFloat,
        trailingAnchor: NSLayoutAnchor<NSLayoutXAxisAnchor>, trailingConstant: CGFloat,
        leadingAnchor: NSLayoutAnchor<NSLayoutXAxisAnchor>, leadingConstant: CGFloat)
    {
        self.isUserInteractionEnabled = true
        self.contentMode = .scaleToFill
        self.topAnchor.constraint(equalTo: topAnchor, constant: topConstant).isActive = true;
        self.bottomAnchor.constraint(equalTo: bottomAnchor, constant: bottomConstant).isActive = true;
        self.trailingAnchor.constraint(equalTo: trailingAnchor, constant: trailingConstant).isActive = true;
        self.leadingAnchor.constraint(equalTo:  leadingAnchor, constant: leadingConstant).isActive = true;
    }

    public func setLabels(weightedTags: [String: Int], selectedTags: [String]) {
        let buttons : [UIButton] = createButtons(weightedTags: weightedTags);
        createLayout(buttons: buttons)
    }

    private func createButton(buttonText: String) -> UIButton {
        let button = UIButton()
        button.setTitle(buttonText, for: .normal)
        button.setTitleColor(.black, for: .normal)
        button.titleLabel?.font = UIFont(name: "Avenir-Light", size: 20.0)
        button.translatesAutoresizingMaskIntoConstraints = false;
        self.addSubview(button)
        button.frame = CGRect(x:0,y:0,width:button.intrinsicContentSize.width, height: button.intrinsicContentSize.height)
        button.addTarget(self, action: #selector(self.onButtonPresed(_:)), for: .touchUpInside);
        return button;
    }

    @objc func onButtonPresed(_ sender: UIButton) {
        // guard let label = sender.titleLabel else {return}
        print("Button : \(sender) poressed")
    }

    private func createButtons(weightedTags: [String: Int]) -> [UIButton] {
        var buttons : [UIButton] = [];
        for tag in weightedTags {
            buttons.append(createButton(buttonText: tag.key))
        }
       return buttons;
    }


    private func createLayout(buttons : [UIButton]) {
        if buttons.count == 0 { return }
        let topPadding : CGFloat = 30;
        let sidePadding : CGFloat = 32;

        let padding : CGFloat = 10;
        let availableHeight : CGFloat = self.frame.height + (-2 * topPadding)
        let availableWidth : CGFloat = self.frame.width + (-2 * sidePadding)

        var i = 0;

        var totalHeight : CGFloat = topPadding
        var rowLength : CGFloat = 0;
        var rowCount : Int = 0;
        var lastButton : UIButton!


        for button in buttons {
            if totalHeight > availableHeight { print("Cloud out of space"); return }
            let buttonWidth = button.intrinsicContentSize.width;
            let buttonHeight = button.intrinsicContentSize.height;

            if rowLength == 0 && rowCount == 0
            {
                print("FirstButtonLabel  \(String(button.titleLabel!.text!))")
                setFirstButtonConstraint(button: button, totalHeight: totalHeight, sidePadding: sidePadding)
                rowLength += buttonWidth + sidePadding + 5; // FIX annoying first row image overlap
            }
            else if rowLength + buttonWidth + padding < availableWidth
            {
                setConstraint(button: button, lastButton: lastButton, totalHeight: totalHeight, padding: padding)
                rowLength += buttonWidth + padding;
            }
            else
            {
                print("Out of space")
                totalHeight += buttonHeight + padding
                rowLength = buttonWidth + sidePadding;
                rowCount += 1;
                setNewRowConstraint(button: button, totalHeight:totalHeight , sidePadding: sidePadding)
            }
            i += 1;
            lastButton = button
            print(button.isUserInteractionEnabled)
            print(button.allTargets)
            print(button)
        }
    }
    private func setFirstButtonConstraint(button: UIButton, totalHeight: CGFloat, sidePadding: CGFloat) {
        button.topAnchor.constraint(equalTo: self.topAnchor, constant: totalHeight).isActive = true;
        button.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: sidePadding + 5).isActive = true;
    }
    private func setConstraint(button: UIButton, lastButton: UIButton, totalHeight: CGFloat, padding:CGFloat) {
        button.leadingAnchor.constraint(equalTo: lastButton.trailingAnchor, constant: padding).isActive = true;
        button.topAnchor.constraint(equalTo: self.topAnchor, constant: totalHeight).isActive = true;
    }
    private func setNewRowConstraint(button: UIButton, totalHeight: CGFloat, sidePadding: CGFloat) {
        button.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: sidePadding).isActive = true;
        button.topAnchor.constraint(equalTo: self.topAnchor, constant: totalHeight).isActive = true;
    }
}

Операторы Print обеспечивают следующий вывод:

true
[AnyHashable(<unFatMobile.SuggenstionCloud: 0x7fb5fae028e0; baseClass = UIImageView; frame = (10 280; 375 317); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x6000005de920>>)]
<UIButton: 0x7fb5fac2d840; frame = (0 0; 41 40); opaque = NO; layer = <CALayer: 0x6000005d0fe0>> 

Думаю, что-то не так с методами жизненного цикла класса.

1 Ответ

0 голосов
/ 31 декабря 2018

Я вижу, что на это уже ответили в комментариях, но немного фона.

Когда пользователь нажимает на экран, это событие верхнего уровня, которое получает событие.Если для свойства isUserInteractionEnabled установлено значение true, то он выполняет свое стандартное действие (каждый UIView может выполнять что-то по-разному при касании.) Стандартное действие базового UIView состоит в том, чтобы выяснить, какое подпредставление было задействовано, как передать событие этому подпредставлению.Таким образом, событие касания идет вниз по иерархии представлений от самых общих к наиболее конкретным.

Если в какой-то момент представление отключило взаимодействие с пользователем, то оно откажется выполнять свое стандартное действие, которое включает в себя не передачу события ни в одно из его подпредставлений.

Другой способ случайносделать UIButton не записываемым на пленку - это нарисовать его за пределами родительского представления.Представления передают события только тем вложенным представлениям, которые были нарисованы в своих границах.

...