SwiftUI - как получить координату / положение нажатой кнопки - PullRequest
3 голосов
/ 10 октября 2019

Короткая версия: Как получить координаты нажатой Button в SwiftUI?

Я ищу что-то вроде этого (псевдокод), где geometry.x - этоположение нажатой кнопки в текущем виде:

GeometryReader { geometry in      
     return Button(action: { self.xPos = geometry.x}) {  
          HStack {               
               Text("Sausages")  
          }  
     }  
}

Длинная версия: Я начинаю SwiftUI и Swift, поэтому задаюсь вопросом, как лучше всего достичь этого концептуально.

Чтобы привести конкретный пример, с которым я играю:

Представьте себе систему вкладок, в которой я хочу переместить индикатор подчеркивания в положение нажатой кнопки.

[в сторону] Есть ответв этом посте это визуально делает то, к чему я иду, но это кажется довольно сложным: Как сделать размер другого представления в SwiftUI [/ aside]

Вот моя внешняя структура, котораястроит панель вкладок и прямоугольник (текущий индикатор), который я пытаюсь изменить размер и положение:


import SwiftUI
import UIKit

struct TabBar: View {

    var tabs:ITabGroup
    @State private var selected = "Popular"
    @State private var indicatorX: CGFloat = 0
    @State private var indicatorWidth: CGFloat = 10
    @State private var selectedIndex: Int = 0

    var body: some View {
        ScrollView(.horizontal) {
            HStack(spacing: 0) {
                ForEach(tabs.tabs) { tab in
                    EachTab(tab: tab, choice: self.$selected, tabs: self.tabs, x: self.$indicatorX, wid: self.$indicatorWidth)
                }
            }.frame(minWidth: 0, maxWidth: .infinity, minHeight: 40, maxHeight: 40).padding(.leading, 10)
                .background(Color(UIColor(hex: "#333333")!))
            Rectangle()
                .frame(width: indicatorWidth, height: 3 )
                .foregroundColor(Color(UIColor(hex: "#1fcf9a")!))
            .animation(Animation.spring())
        }.frame(height: 43, alignment: .leading)
    }
}

Вот моя структура, которая создает каждый элемент вкладки и включает в себя вложенный func, чтобы получить ширинувыбранный элемент:

struct EachTab: View {
    // INCOMING!
    var tab: ITab
    @Binding var choice: String
    var tabs: ITabGroup
    @Binding var x: CGFloat
    @Binding var wid: CGFloat
    @State private var labelWidth: CGRect = CGRect()

    private func tabWidth(labelText: String, size: CGFloat) -> CGFloat {
        let label = UILabel()
        label.text = labelText
        label.font = label.font.withSize(size)
        let labelWidth = label.intrinsicContentSize.width
        return labelWidth
    }

    var body: some View {
        Button(action: { self.choice = self.tab.title; self.x = HERE; self.wid = self.tabWidth(labelText: self.choice, size: 13)}) {
            HStack {
                // Determine Tab colour based on whether selected or default within black or green rab set
                if self.choice == self.tab.title {
                    Text(self.tab.title).foregroundColor(Color(UIColor(hex: "#FFFFFF")!)).font(.system(size: 13)).padding(.trailing, 10).animation(nil)
                } else {
                    Text(self.tab.title).foregroundColor(Color(UIColor(hex: "#dddddd")!)).font(.system(size: 13)).padding(.trailing, 10).animation(nil)
                }
            }
        }
        // TODO: remove default transition fade on button click
    }
}

Создание не SwiftUI UILabel, чтобы получить ширину Button, кажется немного проблематичным. Есть ли лучший способ?

Есть ли простой способ получить координаты нажатого SwiftUI Button?

Ответы [ 3 ]

1 голос
/ 16 октября 2019
struct ContentView: View {

var body: some View {
    VStack {
        Button(action: { print("Button pressed")}) { Text("Button") }
    }.simultaneousGesture(DragGesture(minimumDistance: 0, coordinateSpace: .global)
        .onEnded { print("Changed \($0.location)") })
}
}

Это решение, кажется, работает, добавьте одновременный жест на кнопку, к сожалению, оно не работает, если кнопка находится в форме

1 голос
/ 13 октября 2019

Вы можете использовать распознаватель DragGesture с минимальным расстоянием перетаскивания 0, который предоставляет вам информацию о местоположении. Однако, если вы объедините DragGesture с вашей кнопкой, жест перетаскивания не будет срабатывать при обычном нажатии кнопки. Он будет срабатывать только тогда, когда перетаскивание заканчивается за пределами кнопки.

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

В этом случае вид будет выглядеть так:

struct MyView: View {

    @State var xPos: CGFloat = 0

    var body: some View {
        GeometryReader { geometry in
            HStack {
                Text("Sausages: \(self.xPos)")
            }
        }.gesture(DragGesture(minimumDistance: 0, coordinateSpace: .global).onEnded { dragGesture in
            self.xPos = dragGesture.location.x
        })
    }
}

Параметр coordinateSpace указывает, требуется ли позиция касания в .local или .global пробеле. В локальном пространстве положение относительно представления, к которому вы прикрепили жест. Например, если бы у меня был вид Text в середине экрана, моя локальная позиция y была бы почти 0, тогда как мой глобальный y был бы половиной высоты экрана.

ЭтоЯ немного сбил меня с толку, но этот пример показывает идею:

struct MyView2: View {

    @State var localY: CGFloat = 0
    @State var globalY: CGFloat = 0

    var body: some View {
        VStack {
            Text("local y: \(self.localY)")
                .gesture(DragGesture(minimumDistance: 0, coordinateSpace: .local).onEnded { dragGesture in
                    self.localY = dragGesture.location.y
                })

            Text("global y: \(self.globalY)")
                .gesture(DragGesture(minimumDistance: 0, coordinateSpace: .global).onEnded { dragGesture in
                    self.globalY = dragGesture.location.y
                })
        }
    }
}
0 голосов
/ 17 октября 2019

Оказывается, я решил эту проблему, адаптировав пример на https://swiftui -lab.com / Communication-with-the-View-Tree-Part-2 /

СутьТехника использует anchorPreference, которая является средством отправки данных об одном представлении обратно по цепочке к наследственным представлениям. Я не смог найти никаких документов по этому вопросу в мире Apple, но могу засвидетельствовать, что это работает.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...