SwiftUI-iPadOS 및 Catalyst에서 마우스 / 트랙 패드와 함께 onTapGesture를 사용하는 예기치 않은 동작

themathsrobot

내 앱에는 직사각형 카드 목록을 표시하는 레이아웃이 있습니다. 각 카드는 작업 버튼 세트와 추가 정보 등을 표시하기 위해 탭할 수 있어야합니다 (한 번).

내가 사용하여이를 구현 .onTapGesture()하고 또한 뒀다 .contentShape(Rectangle()tappable 영역을 적용 할 수 있습니다. 그러나 내 구현은 터치 스크린 인터페이스에서 잘 작동하지만 iPadOS 마우스 지원과 함께 사용할 때 Catalyst에서 그 문제에 대해 매우 예기치 않은 동작이 나타납니다.

문제를 재현하기 위해 복사 할 수있는 재현 가능한 최소한의 예를 아래에 만들었습니다.

마우스 / 트랙 패드 입력을 사용할 때 문제가있는 경우 :

  • 모든 마우스 클릭이 탭 제스처로 기록되는 것은 아닙니다. 이것은 몇 가지 경우를 제외하고는 대부분 임의적으로 발생합니다.
  • 매우 특정 영역에서만 클릭하거나 동일한 지점에서 여러 번 클릭 할 때 클릭하는 것 같습니다.
  • 대부분의 경우 다른 모든 클릭 만 기록 되는 것 같습니다 . 그래서 두 번 클릭하여 한 번의 탭 제스처 만 얻습니다.
  • 이 예제 코드에서는 분명하지 않지만 내 메인 앱에서 탭할 수있는 영역은 겉보기에 임의적으로 보입니다. 일반적으로 텍스트 근처를 클릭하거나 탭 제스처를 기록하기 위해 텍스트와 정렬하여 클릭 할 수 있지만 항상 그런 것은 아닙니다 .

예제 코드를 실행하는 경우 마우스를 반복적으로 이동하고 한 번의 클릭을 시도하여 문제를 확인할 수 있습니다. 같은 지점을 여러 번 클릭하지 않으면 작동하지 않습니다.

무엇 예상대로 작업을 수행합니다 :

  • 마우스 대신 터치를 사용한 모든 입력; 탭하는 위치에 관계없이 탭 제스처를 기록합니다.
  • 기본 Mac 대상으로 실행할 때 마우스 입력. 위에서 언급 한 문제는 iPadOS 및 Mac Catalyst에서 예제를 실행할 때 마우스 / 트랙 패드에만 해당됩니다.

이 문제를 재현하는 데 사용한 코드 (탭 제스처가 기록 될 때마다 계산하는 카운터가 있음) :

struct WidgetCompactTaskItemView: View {
    
    let title: String
    let description: String
    
    var body: some View {
        HStack {
            Rectangle()
                .fill(Color.purple)
                .frame(maxWidth: 14, maxHeight: .infinity)
            VStack(alignment: .leading) {
                Text(title).font(.system(size: 14, weight: .bold, design: .rounded))
                Text(description).font(.system(.footnote, design: .rounded))
                    .frame(maxHeight: .infinity)
                    .fixedSize(horizontal: false, vertical: true)
                    .lineLimit(1)
                    .padding(.vertical, 0.1)
                Spacer()
            }
            .padding(.horizontal, 6)
            .padding(.top, 12)
        }
        .frame(maxWidth: .infinity, maxHeight: 100, alignment: .leading)
        .background(Color.black)
        .cornerRadius(16)
        .overlay(
                RoundedRectangle(cornerRadius: 16)
                    .stroke(Color.green, lineWidth: 0.5)
            )
    }
}

struct ContentView: View {
    @State var tapCounter = 0
    var body: some View {
        VStack {
            Text("Button tapped \(tapCounter) times.")
            WidgetCompactTaskItemView(title: "Example", description: "Description")
                .contentShape(Rectangle())
                .onTapGesture(count: 1) {
                    tapCounter += 1
                }
            Spacer()
        }
     }
}

수정자를 이동하고 수정 자 eoFill에서 true로 설정 하는 등 여러 가지 시도를 contentShape해봤습니다 (문제를 해결하지는 않았지만 예상치 못한 동작을 다르게 만들었습니다).

예상대로 작동하고 마우스 나 터치에 관계없이 일관되게 작동 하는 솔루션 을 찾는 데 도움 이 될 것입니다. 내가 잘못하고 있는지 또는 여기에 버그가 있는지 확실하지 않으므로 코드를 사용하여이 예제를 직접 다시 만들어 문제를 재현 할 수 있는지 확인하십시오.

themathsrobot

그래서 저는 .onTapGesture마우스 입력으로 저에게 있었던 모든 이상한 점을 우회 할 수있는 훨씬 더 나은 솔루션이 있다는 것을 깨달았습니다 . Button대신 전체보기를 캡슐화했습니다 .

나는 이것을 onTapGesture와 유사한 수정 자로 만들어 훨씬 더 실용적입니다.


import Foundation
import SwiftUI

public struct UltraPlainButtonStyle: ButtonStyle {
    public func makeBody(configuration: Self.Configuration) -> some View {
        configuration.label
    }
}

struct Tappable: ViewModifier {
    let action: () -> ()
    func body(content: Content) -> some View {
        Button(action: self.action) {
            content
        }
        .buttonStyle(UltraPlainButtonStyle())
    }
}

extension View {
    func tappable(do action: @escaping () -> ()) -> some View {
        self.modifier(Tappable(action: action))
    }
}

이것을 통해 : 먼저 레이블을 그대로 반환하는 버튼 스타일이 있습니다. PlainButtonStyle()클릭하면 기본값이 여전히 가시적 효과를 가지기 때문에 필요합니다 . 그런 다음 Button이 버튼 스타일 을 사용하여에 제공된 콘텐츠를 캡슐화하는 수정자를 만든 다음 확장으로 View.

사용 예

WidgetCompactTaskItemView(title: "Example", description: "Description")
                .tappable {
                    tapCounter += 1
                }

이것은 마우스를 사용하여 클릭 가능한 영역에서 겪었던 모든 문제를 해결했습니다.

이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.

침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제

에서 수정
0

몇 마디 만하겠습니다

0리뷰
로그인참여 후 검토

관련 기사

Related 관련 기사

뜨겁다태그

보관