在 SwiftUI 中拖动分隔符 [英] Drag separators in SwiftUI

查看:31
本文介绍了在 SwiftUI 中拖动分隔符的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我将如何使用纯 SwiftUI 在视图或 UIViews 之间添加可拖动的分隔线.甚至可以使用 SwiftUI,还是我必须依靠 UIKit?

带有分隔符的示例屏幕:

我在 SwiftUI 文档中找不到这种东西.即使只是足够的信息来完成左上角的两窗格示例也会很有用.

(在

//可调整大小的窗格,红色始终可见结构窗格视图:查看{静态让 startWidth = UIScreen.main.bounds.size.width/6静态让 startHeight = UIScreen.main.bounds.size.height/5//拖动紫色手柄时更新拖动宽度@State 私有变量 dragWidth : CGFloat = startWidth//拖动橙色手柄时更新拖动高度@State 私有变量 dragHeight : CGFloat = startHeight//记住显示/隐藏绿色和蓝色窗格@AppStorage("show") var show : Bool = true//根据设备分辨率保持窗格的合理大小var minWidth : CGFloat = UIScreen.main.bounds.size.width/6让 minHeight : CGFloat = UIScreen.main.bounds.size.height/5//紫色和橙色的手柄这么厚让厚度:CGFloat = 9//在适当的时候显示调整大小的计算属性var showResize : Bool {dragWidth != PanesView.startWidth ||dragHeight != PanesView.startHeight}//使用计算属性来保持 body 整洁var主体:一些视图{HStack(间距:0){红窗格//为什么有两个show-if?动画追逐非动画并增加视觉趣味如果显示{紫色握把}如果显示 { withAnimation {VStack(间距:0){绿色窗格橙色握把Color.blue.frame(height: dragHeight)//蓝色窗格}.frame(宽度:dragWidth)} }}}var redPane:一些视图{ZStack(对齐:对齐(水平:.trailing,垂直:.top)){红色//显示和隐藏绿色和蓝色窗格,两个夹点切换(isOn:$show.animation(),标签:{//根据切换位置更改图标图像(系统名称:显示?眼睛":eye.slash").font(.title).foregroundColor(.primary)}).frame(宽度:100).填充()}}var PurpleGrip:一些视图{颜色.紫色.frame(宽度:厚度).手势(拖动手势().onChanged { 手势输入让 screenWidth = UIScreen.main.bounds.size.width//当拖动继续更新状态时,框架会提供很小的增量让 delta = 手势.translation.width//确保拖动宽度有界dragWidth = max(dragWidth - delta, minWidth)dragWidth = min(screenWidth - 厚度 - minWidth,dragWidth)})}var greenPane:一些视图{ZStack(对齐:对齐(水平:.center,垂直:.top)){颜色.绿色//重置为原始大小如果 showResize { withAnimation {按钮(动作:{ withAnimation {dragWidth = UIScreen.main.bounds.size.width/6dragHeight = UIScreen.main.bounds.size.height/5} }, 标签: {图像(系统名称:uiwindow.split.2x1").font(.title).foregroundColor(.primary).填充()}).buttonStyle(PlainButtonStyle())}}}}var orangeGrip : 一些视图 {颜色为橙色.frame(高度:厚度).手势(拖动手势().onChanged { 手势输入让 screenHeight = UIScreen.main.bounds.size.height让 delta = 手势.translation.heightdragHeight = max(dragHeight - delta, minHeight)dragHeight = min(screenHeight - 厚度 - minHeight,dragHeight)})}}

How would I add draggable separator lines between Views or UIViews using purely SwiftUI. Is it even possible with SwiftUI, or would I have to fall back on UIKit?

Example screens with separators:

I can't find this kind of stuff in the SwiftUI documentation. Even just enough info to do the top-left two-pane example would be useful.

(Similar questions have been asked here and here , but these are 5 and 7 years old, and deal with Objective-C / UIKit, not Swift / SwiftUI)

解决方案

Here is a sample that allows horizontal and vertical resizing using grips. Dragging the purple grip resizes horizontally and the orange grip vertically. Both vertical and horizontal sizes are bounded by device resolution. The red pane is always visible, but the grips and other panes can be hidden using a toggle. There is also a reset button to restore, it is only visible when the original state changes. There are other tidbits that are useful and commented inline.

// Resizable panes, red is always visible
struct PanesView: View {
    static let startWidth = UIScreen.main.bounds.size.width / 6
    static let startHeight = UIScreen.main.bounds.size.height / 5
    // update drag width when the purple grip is dragged
    @State private var dragWidth : CGFloat = startWidth
    // update drag height when the orange grip is dragged
    @State private var dragHeight : CGFloat = startHeight
    // remember show/hide green and blue panes
    @AppStorage("show") var show : Bool = true
    // keeps the panes a reasonable size based on device resolution
    var minWidth : CGFloat = UIScreen.main.bounds.size.width / 6
    let minHeight : CGFloat = UIScreen.main.bounds.size.height / 5
    // purple and orange grips are this thick
    let thickness : CGFloat = 9
    // computed property that shows resize when appropriate
    var showResize : Bool {
        dragWidth != PanesView.startWidth || dragHeight != PanesView.startHeight
    }

    // use computed properties to keep the body tidy
    var body: some View {
        HStack(spacing: 0) {
            redPane
            // why two show-ifs? the animated one chases the non-animated and adds visual interest
            if show {
                purpleGrip
            }
            if show { withAnimation {
                VStack(spacing: 0) {
                    greenPane
                    orangeGrip
                    Color.blue.frame(height: dragHeight) // blue pane
                }
                .frame(width: dragWidth)
            } }
        }
    }
    
    var redPane : some View {
        ZStack(alignment: Alignment(horizontal: .trailing, vertical: .top)) {
            Color.red
            // shows and hides the green and blue pane, both grips
            Toggle(isOn: $show.animation(), label: {
                // change icon depending on toggle position
                Image(systemName: show ? "eye" : "eye.slash")
                    .font(.title)
                    .foregroundColor(.primary)
            })
            .frame(width: 100)
            .padding()
        }
    }
    
    var purpleGrip : some View {
        Color.purple
            .frame(width: thickness)
            .gesture(
                DragGesture()
                    .onChanged { gesture in
                        let screenWidth = UIScreen.main.bounds.size.width
                        // the framework feeds little deltas as the drag continues updating state
                        let delta = gesture.translation.width
                        // make sure drag width stays bounded
                        dragWidth = max(dragWidth - delta, minWidth)
                        dragWidth = min(screenWidth - thickness - minWidth, dragWidth)
                    }
            )
    }
    
    var greenPane : some View {
        ZStack(alignment: Alignment(horizontal: .center, vertical: .top)) {
            Color.green
            // reset to original size
            if showResize { withAnimation {
                Button(action: { withAnimation {
                    dragWidth = UIScreen.main.bounds.size.width / 6
                    dragHeight = UIScreen.main.bounds.size.height / 5
                } }, label: {
                    Image(systemName: "uiwindow.split.2x1")
                        .font(.title)
                        .foregroundColor(.primary)
                        .padding()
                })
                .buttonStyle(PlainButtonStyle())
            }}
        }
    }
    
    var orangeGrip : some View {
        Color.orange
            .frame(height: thickness)
            .gesture(
                DragGesture()
                    .onChanged { gesture in
                        let screenHeight = UIScreen.main.bounds.size.height
                        let delta = gesture.translation.height
                        dragHeight = max(dragHeight - delta, minHeight)
                        dragHeight = min(screenHeight - thickness - minHeight, dragHeight)
                    }
            )
    }
}

这篇关于在 SwiftUI 中拖动分隔符的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆