Почему мой UIButton не полностью доступен для нажатия (UIKit в Swift)

Это моя кнопка:

import UIKit

class PassButton: UIButton {

    var videoVC: VideoGameVC?
    
    required init(isEnabled: Bool = false) {
        super.init(frame: .zero)
        
        self.isEnabled = true
        self.addTarget(self, action: #selector(pressed(_:)), for: .touchUpInside)

        let imageViewBackground = UIImageView(frame: CGRect(x:0, y:0, width: 70, height: 80))
        imageViewBackground.image = UIImage(named: "pass_button")
        imageViewBackground.contentMode = UIView.ContentMode.scaleAspectFill
        addSubview(imageViewBackground)
        sendSubviewToBack(imageViewBackground)
        
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    @objc func pressed(_ sender: UIButton) {
        print("presovan")
    }
   
    
}

и вот как я добавляю его в другой контроллер представления:

func configPassButton() {
        passButton = PassButton()
        guard let passButton = passButton else { return }
        view.addSubview(passButton)
        passButton.translatesAutoresizingMaskIntoConstraints = false
        passButton.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 20).isActive = true
        passButton.leftAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leftAnchor, constant: 20).isActive = true
        
        
    }

он отображается так, как я хочу, но область, которую можно коснуться, очень мала. Постукивать можно только в верхнем левом углу, причем очень маленьком (около 10% всей поверхности). Как я могу исправить, чтобы все можно было нажимать?

addSubview(imageViewBackground), подумайте, что это представление блокирует... Вы можете использовать иерархию представлений отладки, и вы можете это увидеть.
Larme 29.08.2024 00:33

@ Ларме, ты прав. Однако imageViewBackground является частью кнопки, разве он не должен быть также доступен для нажатия? Я не понимаю...

Vladimir Despotovic 29.08.2024 00:54

@VladimirDespotovic, пожалуйста, проверьте это stackoverflow.com/a/78422934/23301405

Immanuel 29.08.2024 07:59

@VladimirDespotovic - «imageViewBackground является частью кнопки, разве на нее тоже нельзя нажимать?» -- нет... вы добавили подпредставление, выходящее за пределы кнопки. Вам следует использовать .setBackgroundImage. Если вам нужна «кнопка изображения» с .scaleAspectFill, вам нужно сначала изменить размер и обрезать изображение или использовать UIImageView и добавить жест касания.

DonMag 30.08.2024 15:21
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
4
58
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вместо того, чтобы вручную добавлять подпредставление для фонового изображения, возможно, используйте свойство .setBackgroundImage() кнопки. Кроме того, размер кадра был установлен для ImageView, но, если я не заметил этого, размер кадра не был установлен для самой кнопки. Возможно, поэтому область нажатия кнопки не полностью соответствует размеру изображения.

Чтобы исправить это, удалите эти строки, устанавливающие фоновое изображение:

let imageViewBackground = UIImageView(frame: CGRect(x:0, y:0, width: 70, height: 80))
imageViewBackground.image = UIImage(named: "pass_button")
imageViewBackground.contentMode = UIView.ContentMode.scaleAspectFill
addSubview(imageViewBackground)
sendSubviewToBack(imageViewBackground) 

И замените приведенные выше строки этими, чтобы установить фоновое изображение кнопки, режим содержимого, ширину и высоту:

self.setBackgroundImage(UIImage(named: "pass_button"), for: .normal)
self.layoutIfNeeded()
self.subviews.first?.contentMode = .scaleAspectFill
self.widthAnchor.constraint(equalToConstant: 70).isActive = true
self.heightAnchor.constraint(equalToConstant: 80).isActive = true

После этих изменений кнопка должна стать полностью доступной для нажатия.

Другой вариант

Мне только что пришло в голову, что если вы хотите использовать подпредставление imageViewBackground вместо .setBackgroundImage(), установка размера кнопки, а затем обрезка фонового изображения также будет работать. Например, добавив это после sendSubviewToBack():

self.widthAnchor.constraint(equalToConstant: 70).isActive = true
self.heightAnchor.constraint(equalToConstant: 80).isActive = true
self.clipsToBounds = true
Ответ принят как подходящий

Предположим, у вас есть изображение с соотношением сторон 70:80. например это:

Ваш код отображает это следующим образом:

но, как вы знаете, вы можете нажать только в верхнем левом углу.

Если мы добавим к кнопке красную рамку в 2 точки:

passButton.layer.borderColor = UIColor.red.cgColor
passButton.layer.borderWidth = 2

это выглядит так:

рамка кнопки - это только 30 x 34 ... и 70 x 80 imageView выходит за пределы кнопки. Таким образом, можно нажать только на саму рамку кнопки.

Если вы задаете ограничения ширины и высоты кнопки:

passButton.widthAnchor.constraint(equalToConstant: 70.0).isActive = true
passButton.heightAnchor.constraint(equalToConstant: 80.0).isActive = true

то мы видим это:

и всю кнопку можно нажать.

Однако добавление UIImageView в качестве подпредставления — ужасный подход.

Гораздо более уместно установить свойство фонового изображения:

// safely handle optional
if let img = UIImage(named: "pass_button") {
    setBackgroundImage(img, for: [])
}

Опять же, нам также необходимо установить ограничения ширины и высоты, но теперь мы используем «стандартную» кнопку вместо подкласса с добавленными подпредставлениями:

let passButton = UIButton()

passButton.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(passButton)

NSLayoutConstraint.activate([
    passButton.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 20.0),
    passButton.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 20.0),
    passButton.widthAnchor.constraint(equalToConstant: 70.0),
    passButton.heightAnchor.constraint(equalToConstant: 80.0),
])

if let img = UIImage(named: "pass_button") {
    passButton.setBackgroundImage(img, for: [])
}

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

Другие вопросы по теме