【问题标题】:.clipShape lose alignment when padding | SwiftUI | iOS15.clipShape 在填充时失去对齐 | SwiftUI | iOS15
【发布时间】:2022-02-10 03:33:28
【问题描述】:

我正在开发自定义导航底部栏。我希望它是浮动的,但我意识到当我在其上添加 .padding() 时,其背景中的 .clipShape() 会失去对齐。

我已经编写了这个问题的简单版本。

没有填充的底部导航:

带内边距的底部导航:

主视图:

struct ContentView: View {
var body: some View {
        VStack{
            Spacer()
            CustomBottomNav()
                .padding() // <- THIS MAKE THE SHAPE TO LOSE ALIGN
        }
}

自定义底部导航:

struct CustomBottomNav: View {

@State var selectedTab: Views = .HOME
@State private var xAxis: CGFloat = 0
@Namespace var animation

private let tabs: [Views] = [.SETTINGS, .RANKING, .HOME, .SALES, .SEARCHER]
private let iconSize: CGFloat = 25

private func isSelectedTab(_ tab: Views) -> Bool{
    return selectedTab == selectedTab
}

var body: some View {
    HStack(spacing: 0){
        ForEach(tabs, id: \.self){ tab in
            
            GeometryReader { geo in
                Button {
                    
                    print(geo.frame(in: .global).midX)
                    
                    withAnimation(.spring()) {
                        selectedTab = tab
                        xAxis = geo.frame(in: .global).midX
                    }
                } label: {
                    getImage(tab: tab)
                        .resizable()
                        .renderingMode(.template)
                        .aspectRatio(contentMode: .fit)
                        .frame(width: 30, height: 30)
                        .padding(isSelectedTab(tab) ? 15 : 0)
                        .background(
                            Color.orange
                                .opacity(
                                    isSelectedTab(tab) ? 1 : 0
                                ).clipShape(Circle())
                        )
                        .matchedGeometryEffect(id: tab, in: animation)
                }
                .position(x: geo.frame(in: .local).midX, y: geo.frame(in: .local).midY)
                .offset(
                    y: -60
                )
                .onAppear {
                    if isSelectedTab(tab) {
                        xAxis = geo.frame(in: .global).midX
                    }
                }
            }
            .frame(width: iconSize, height: iconSize)
            .overlay(
                Rectangle()
                    .stroke(.red)
            )
            
            if tab != tabs.last{
                Spacer()
            }

        }
    }
    .padding(.horizontal, 30)
    .padding(.vertical)
    .background(
        Color.yellow
            .clipShape(BottomNavShape(xAxis: xAxis))
            .cornerRadius(15)
    )
}

func getImage(tab: Views) -> Image {
    switch tab {
        case .SETTINGS:
            return Image("house")
        case .RANKING:
            return Image("house")
        case .HOME:
            return Image("house")
        case .SALES:
            return Image("house")
        case .SEARCHER:
            return Image("house")
    }
}

enum Views{
    case SETTINGS
    case RANKING
    case HOME
    case SALES
    case SEARCHER
    
}
}

底部导航形状:

struct BottomNavShape: Shape{

var xAxis: CGFloat

//Animating path
var animatableData: CGFloat{
    get{
        return xAxis
    }
    set{
        xAxis = newValue
    }
}

func path(in rect: CGRect) -> Path {
    return Path{ path in
        path.move(to: CGPoint(x: 0, y: 0))
       path.addLine(to: CGPoint(x: rect.width, y: 0))
       path.addLine(to: CGPoint(x: rect.width, y: rect.height))
       path.addLine(to: CGPoint(x: 0, y: rect.height))
       
       let center = CGPoint(x: xAxis, y: rect.midY)
       
        path.move(to: center)
       
        path.addArc(center: center, radius: 15, startAngle: .degrees(0), endAngle: 
.degrees(1), clockwise: true)
    }
}
}

这些类是复制问题所需的全部。

我正在使用 XCode 13 和 iOS 15。

【问题讨论】:

  • 尝试摆脱硬编码偏移
  • 偏移量是由于原始代码,选中时圆圈向上。在这个简单的版本中总是向上的。

标签: ios swift swiftui padding


【解决方案1】:

由于硬编码值,它有点棘手,但是 我让它像这样工作:

如果您在外部视图上使用定义的填充,例如

.padding(30)

那么您可以在此处在 CustomButtonNav 中减去该值:

xAxis = geo.frame(in: .global).midX - 30 // subtract your outer padding here

这出现了 2 次:
在按钮操作和.onAppear

【讨论】:

  • 好的,可以。谢谢。但这对我来说真的没有意义。并添加一些填充值以便稍后提取它......这很丑:/
  • 其实真的不行。如果底部导航的 maxWidth 是 .infinity 那么唯一的分隔是填充,你可以减去它。但是在 iPad 中我有一个不同的 maxWidth,所以它在那里遇到了同样的问题。这不是一个真正干净的解决方案。
  • 它在 iPad 上运行良好。您没有在问题中提到不同的 maxWidth 。但是您仍然可以将填充减法传递到子视图中,并在较大的设备上跳过它。
  • 我在本地环境中使用全局坐标,这就是问题所在。我已经发布了解决方案。
【解决方案2】:

问题是您将全局坐标传递给 BottomNavShape,后者使用局部坐标来绘制自身。

因此,传递给 BottomNavShape 的全局 X = 30 坐标将是 后 30 个点,BottomNavShape 的 minX 在全局上下文中开始。

为了解决这个问题,我将 xAxis 更改为 xAxisMultiplier

我做了这个函数:

    func setAxisMultiplier(_ index: Int){
        xAxisMultiplier = CGFloat(index) / CGFloat(tabs.count - 1)
    }

其中indextabs

tab的索引

我向 BottomNavShape 添加了两个参数:horizo​​ntalPaddingiconSize

底部导航形状

struct BottomNavShape: Shape{

var xAxisMultiplier: CGFloat
var horizontalPadding: CGFloat
var iconSize: CGFloat

//Animating path
var animatableData: CGFloat{
    get{
        return xAxisMultiplier
    }
    set{
        xAxisMultiplier = newValue
    }
}

func path(in rect: CGRect) -> Path {
    return Path{ path in
        path.move(to: CGPoint(x: 0, y: 0))
        path.addLine(to: CGPoint(x: rect.width, y: 0))
        path.addLine(to: CGPoint(x: rect.width, y: rect.height))
        path.addLine(to: CGPoint(x: 0, y: rect.height))

        let xCenter = ((rect.maxX - (horizontalPadding * 2) - iconSize) * xAxisMultiplier) + horizontalPadding + (iconSize * 0.5)

        path.move(to: CGPoint(x: xCenter - 50, y: 0))

        let to1 = CGPoint(x: xCenter, y: 35)
        let control1 = CGPoint(x: xCenter - 25, y: 0)
        let control2 = CGPoint(x: xCenter - 25, y: 35)

        let to2 = CGPoint(x: xCenter + 50, y: 0)
        let control3 = CGPoint(x: xCenter + 25, y: 35)
        let control4 = CGPoint(x: xCenter + 25, y: 0)

        path.addCurve(to: to1, control1: control1, control2: control2)

        path.addCurve(to: to2, control1: control3, control2: control4)
    }
}
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-12-26
    • 1970-01-01
    • 2018-03-04
    • 2021-04-24
    • 2010-12-13
    • 2015-09-28
    • 2017-07-25
    相关资源
    最近更新 更多