SwiftUI - кнопка с изображением кликабельна снаружи - PullRequest
1 голос
/ 04 апреля 2020

У меня есть ScrollView с несколькими кнопками. Кнопка содержит изображение и текст внизу.

Поскольку изображения довольно большие, я использую .scaledToFill и .clipped. И кажется, что «обрезанная» часть изображения по-прежнему кликабельна, даже если она не отображается.

В видео, которое вы видите, я нажимаю кнопку 1, но кнопка 2 срабатывает.

Gif showing the error

Это моя кодировка. Изображение находится внутри вида Карта .

struct ContentView: View {

    @State var useWebImage = false
    @State var isSheetShowing = false
    @State var selectedIndex = 0

    private let images = [
        "https://images.unsplash.com/photo-1478368499690-1316c519df07?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=2706&q=80",
        "https://images.unsplash.com/photo-1507154258-c81e5cca5931?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=2600&q=80",
        "https://images.unsplash.com/photo-1513310719763-d43889d6fc95?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=2734&q=80",
        "https://images.unsplash.com/photo-1585766765962-28aa4c7d719c?ixlib=rb-1.2.1&auto=format&fit=crop&w=2734&q=80",
        "https://images.unsplash.com/photo-1485970671356-ff9156bd4a98?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=2734&q=80",
        "https://images.unsplash.com/photo-1585607666104-4d5b201d6d8c?ixlib=rb-1.2.1&auto=format&fit=crop&w=2700&q=80",
        "https://images.unsplash.com/photo-1577702066866-6c8897d06443?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=2177&q=80",
        "https://images.unsplash.com/photo-1513809491260-0e192158ae44?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=2736&q=80",
        "https://images.unsplash.com/photo-1582092723055-ad941d1db0d4?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=2700&q=80",
        "https://images.unsplash.com/photo-1478264635837-66efba4b74ba?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjF9&auto=format&fit=crop&w=2682&q=80"
    ]

    var body: some View {
        NavigationView {
            ScrollView {
                VStack(spacing: 40) {

                    Text(useWebImage ? "WebImage is used." : "SwiftUI Image is used")
                        .font(.system(size: 18))
                        .bold()
                        .kerning(0.5)
                        .padding(.top, 20)

                    Toggle(isOn: $useWebImage) {
                        Text("Use WebImage")
                            .font(.system(size: 18))
                            .bold()
                            .kerning(0.5)
                            .padding(.top, 20)
                    }

                    ForEach(0..<images.count) { index in
                        Button(action: {
                            self.selectedIndex = index
                            self.isSheetShowing.toggle()
                        }) {
                            Card(imageUrl: self.images[index], index: index, useWebImage: self.$useWebImage)
                        }
                        .buttonStyle(PlainButtonStyle())
                    }
                }
                .padding(.horizontal, 20)
                .sheet(isPresented: self.$isSheetShowing) {
                    DestinationView(imageUrl: self.images[self.selectedIndex], index: self.selectedIndex, useWebImage: self.$useWebImage)
                }
            }
            .navigationBarTitle("Images")
        }
    }
}
struct Card: View {

    let imageUrl: String
    let index: Int
    @Binding var useWebImage: Bool

    var body: some View {
        VStack {
            if useWebImage {
                WebImage(url: URL(string: imageUrl))
                    .resizable()
                    .indicator(.activity)
                    .animation(.easeInOut(duration: 0.5))
                    .transition(.fade)
                    .scaledToFill()
                    .frame(minWidth: 0, maxWidth: .infinity, minHeight: 250, maxHeight: 250, alignment: .center)
                    .cornerRadius(12)
                    .clipped()
            } else {
                Image("image\(index)")
                    .resizable()
                    .aspectRatio(contentMode: .fill)
                    .frame(minWidth: 0, maxWidth: .infinity, minHeight: 250, maxHeight: 250, alignment: .center)
                    .cornerRadius(12)
                    .clipped()
            }

            HStack {
                Text("Image #\(index + 1) (\(useWebImage ? "WebImage" : "SwiftUI Image"))")
                    .font(.system(size: 18))
                    .bold()
                    .kerning(0.5)

                Spacer()
            }
        }
        .padding(2)
        .border(Color(.systemRed), width: 2)
    }
}

У вас есть идея, как решить эту проблему? Я уже пытался использовать .resizable (resizingMode: .tile), но мне нужно сжать изображение, прежде чем я смогу использовать только плитку.

Для получения подробной информации вы также можете найти проект на GitHub GitHub Project

Буду очень признателен за вашу помощь.

1 Ответ

3 голосов
/ 04 апреля 2020

.clipped влияет только на рисунок, и по умолчанию Button имеет весь контент, на который можно кликнуть, независимо от того, что это такое.

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

Вот демонстрация возможного подхода. Протестировано с Xcode 11.4 / iOS 13.4.

enter image description here

Демонстрационный код (упрощенный вариант вашего снимка):

struct ButtonCard: View {

    var body: some View {
        VStack {
            Image("sea")
                .resizable()
                .aspectRatio(contentMode: .fill)
                .frame(minWidth: 0, maxWidth: .infinity, minHeight: 250, maxHeight: 250, alignment: .center)
                .cornerRadius(12)
                .contentShape(Rectangle())    // << define clickable rect !!
                .clipped()

            HStack {
                Text("Image #1")
                    .font(.system(size: 18))
                    .bold()
                    .kerning(0.5)

                Spacer()
            }.allowsHitTesting(false)         // << disable label area !!
        }
        .padding(2)
        .border(Color(.systemRed), width: 2)
    }
}

struct TestClippedButton: View {
    var body: some View {
        Button(action: { print(">> tapped") }) {
            ButtonCard()
        }.buttonStyle(PlainButtonStyle())
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...