AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / coding / 问题 / 79008142
Accepted
Deepak Sharma
Deepak Sharma
Asked: 2024-09-21 04:12:44 +0800 CST2024-09-21 04:12:44 +0800 CST 2024-09-21 04:12:44 +0800 CST

SwiftUI 在视图被拖动时保持背景静止

  • 772

我已经使用 SwiftUI 实现了一个示例视频编辑时间线,但遇到了一些问题。因此,我将问题分解成几个部分,并将每个问题作为单独的问题发布。在下面的代码中,我有一个简单的时间线,它HStack由左间隔、右间隔(表示为简单的黑色)和中间的修剪器 UI 组成。当拖动左右手柄时,修剪器会调整大小。当拖动修剪器手柄时,左右间隔的宽度也会调整。

问题:我希望修剪器中的背景缩略图(当前实现为填充不同颜色的简单矩形)在修剪器调整大小时保持静止。当前,它们会随着修剪器调整大小而移动,如下面的 gif 所示。我该如何修复它?

在此处输入图片描述

import SwiftUI

struct SampleTimeline: View {
    
    let viewWidth:CGFloat = 340 //Width of HStack container for Timeline
   
    @State var frameWidth:CGFloat = 280 //Width of trimmer
    
    var minWidth: CGFloat {
        2*chevronWidth + 10
    } //min Width of trimmer
    
    @State private var leftViewWidth:CGFloat = 20
    @State private var rightViewWidth:CGFloat = 20
    
    var chevronWidth:CGFloat {
        return 24
    }
    
    var body: some View {
        
        HStack(spacing:0) {
            Color.black
                .frame(width: leftViewWidth)
                .frame(height: 70)
            
            HStack(spacing: 0) {
            
                Image(systemName: "chevron.compact.left")
                    .frame(width: chevronWidth, height: 70)
                    .background(Color.blue)
                    .gesture(
                        DragGesture(minimumDistance: 0)
                            .onChanged({ value in
                                leftViewWidth = max(leftViewWidth + value.translation.width, 0)
                                
                                if leftViewWidth > viewWidth - minWidth - rightViewWidth {
                                    leftViewWidth = viewWidth - minWidth - rightViewWidth
                                }
                                   
                                frameWidth = max(viewWidth - leftViewWidth - rightViewWidth, minWidth)
                                
                            })
                            .onEnded { value in
                               
                            }
                    )
        
                Spacer()
                
                Image(systemName: "chevron.compact.right")
                    .frame(width: chevronWidth, height: 70)
                    .background(Color.blue)
                    .gesture(
                        DragGesture(minimumDistance: 0)
                            .onChanged({ value in
                                rightViewWidth = max(rightViewWidth - value.translation.width, 0)
                                
                                if rightViewWidth > viewWidth - minWidth - leftViewWidth {
                                    rightViewWidth = viewWidth - minWidth - leftViewWidth
                                }
                                
                                frameWidth = max(viewWidth - leftViewWidth - rightViewWidth, minWidth)
                            })
                            .onEnded { value in
                              
                            }
                    )
                 
            }
            .foregroundColor(.black)
            .font(.title3.weight(.semibold))
          
            .background {
                
                HStack(spacing:0) {
                    Rectangle().fill(Color.red)
                        .frame(width: 70, height: 60)
                    Rectangle().fill(Color.cyan)
                        .frame(width: 70, height: 60)
                    Rectangle().fill(Color.orange)
                        .frame(width: 70, height: 60)
                    Rectangle().fill(Color.brown)
                        .frame(width: 70, height: 60)
                    Rectangle().fill(Color.purple)
                        .frame(width: 70, height: 60)
                }
                
            }
            .frame(width: frameWidth)
            .clipped()
            
            Color.black
                .frame(width: rightViewWidth)
                .frame(height: 70)
        }
        .frame(width: viewWidth, alignment: .leading)
    }
}

#Preview {
    SampleTimeline()
}

更新:我已设法按如下方式解决问题,但我仍然觉得这只是一种变通方法(因为我已为缩略图视图设置了偏移)。如果您认为有任何更好更准确的解决方案,请发布(例如,使用同时减小修剪器框架宽度的遮罩)。


import SwiftUI

struct SampleTimeline: View {
    
    let viewWidth:CGFloat = 340 //Width of HStack container for Timeline
   
    @State var frameWidth:CGFloat = 280 //Width of trimmer
    
    var minWidth: CGFloat {
        2*chevronWidth + 10
    } //min Width of trimmer
    
    @State private var leftViewWidth:CGFloat = 20
    @State private var rightViewWidth:CGFloat = 20
    @GestureState private var leftEndPanned = false
    @GestureState private var rightEndPanned = false
    
    var chevronWidth:CGFloat {
        return 24
    }
    
    var body: some View {
        
        HStack(spacing:0) {
            Color.clear
                .frame(width: leftViewWidth)
                .frame(height: 70)
            
            HStack(spacing: 0) {
            
                Image(systemName: "chevron.compact.left")
                    .frame(width: chevronWidth, height: 70)
                    .background(Color.blue)
                    .gesture(
                        DragGesture(minimumDistance: 0)
                            .updating($leftEndPanned, body: { _, state, _ in
                                state = true
                            })
                            .onChanged({ value in
                                leftViewWidth = max(leftViewWidth + value.translation.width, 0)
                                
                                if leftViewWidth > viewWidth - minWidth - rightViewWidth {
                                    leftViewWidth = viewWidth - minWidth - rightViewWidth
                                }
                                   
                                frameWidth = max(viewWidth - leftViewWidth - rightViewWidth, minWidth)
                                
                            })
                            .onEnded { value in
                               
                            }
                    )
        
                Spacer()
                
                Image(systemName: "chevron.compact.right")
                    .frame(width: chevronWidth, height: 70)
                    .background(Color.blue)
                    .gesture(
                        DragGesture(minimumDistance: 0)
                            .updating($rightEndPanned, body: { _, state, _ in
                                state = true
                            })
                            .onChanged({ value in
                                rightViewWidth = max(rightViewWidth - value.translation.width, 0)
                                
                                if rightViewWidth > viewWidth - minWidth - leftViewWidth {
                                    rightViewWidth = viewWidth - minWidth - leftViewWidth
                                }
                                
                                frameWidth = max(viewWidth - leftViewWidth - rightViewWidth, minWidth)
                            })
                            .onEnded { value in
                              
                            }
                    )
                 
            }
            .foregroundColor(.black)
            .font(.title3.weight(.semibold))
            .background {
                
                HStack(spacing:0) {
                    Rectangle().fill(Color.red)
                        .frame(width: 70, height: 60)
                    Rectangle().fill(Color.cyan)
                        .frame(width: 70, height: 60)
                    Rectangle().fill(Color.orange)
                        .frame(width: 70, height: 60)
                    Rectangle().fill(Color.brown)
                        .frame(width: 70, height: 60)
                    Rectangle().fill(Color.purple)
                        .frame(width: 70, height: 60)
                }
                .frame(width: viewWidth - leftViewWidth - rightViewWidth, alignment: .leading)
                .offset(x: -leftViewWidth)
                .background(Color.yellow)
                .clipped()
                
            }
            
            
            Color.clear
                .frame(width: rightViewWidth)
                .frame(height: 70)
        }
        .frame(width: viewWidth, alignment: .leading)
    }
}

#Preview {
    SampleTimeline()
}

  • 1 1 个回答
  • 62 Views

1 个回答

  • Voted
  1. Best Answer
    Benzy Neez
    2024-09-21T16:31:18+08:002024-09-21T16:31:18+08:00

    目前,颜色显示在嵌套的背景中HStack。但是,这HStack是移动的,取决于的大小leftViewWidth。因此,尽管您在背景上设置了较小的框架尺寸,但您并没有补偿堆栈的位置。

    我建议使用不同的方法。不要尝试剪切背景,只需保持不变并应用.mask来控制背景中应该可见的部分。

    • 与夹子形状不同,面罩可以加垫。因此,您可以对面罩进行与修剪器相同的调整。
    • 这样,就无需计算可见宽度。但是,如果您需要知道可见宽度以用于视频编辑,则可以使用计算属性来传递它。下面的更新示例包含此计算属性,但已注释掉。

    您之前接受了另一种拖动修剪器的答案GestureState,该答案使用变量来跟踪拖动位置(这是我的答案)。问题中的示例以不同的方式执行。下面的版本基于我之前提供的相同解决方案。我建议,这是一种更简单的方法。

    struct SampleTimeline: View {
        let viewWidth: CGFloat = 340 //Width of HStack container for Timeline
        let chevronWidth: CGFloat = 24
        let minWidth: CGFloat = 10
    
        @State private var leftOffset: CGFloat = 0
        @State private var rightOffset: CGFloat = 0
        @GestureState private var leftDragOffset: CGFloat = 0
        @GestureState private var rightDragOffset: CGFloat = 0
    
        private func leftAdjustment(dragOffset: CGFloat) -> CGFloat {
            let maxAdjustment = viewWidth - rightOffset - (2 * chevronWidth) - minWidth
            return max(0, min(leftOffset + dragOffset, maxAdjustment))
        }
    
        private func rightAdjustment(dragOffset: CGFloat) -> CGFloat {
            let maxAdjustment = viewWidth - leftOffset - (2 * chevronWidth) - minWidth
            return max(0, min(rightOffset - dragOffset, maxAdjustment))
        }
    
    //    private var frameWidth: CGFloat {
    //        viewWidth
    //        - (2 * chevronWidth)
    //        - leftAdjustment(dragOffset: leftDragOffset)
    //        - rightAdjustment(dragOffset: rightDragOffset)
    //    }
    
        var body: some View {
            HStack(spacing: 0) {
    
                Image(systemName: "chevron.compact.left")
                    .frame(width: chevronWidth, height: 70)
                    .background(Color.blue)
                    .offset(x: leftAdjustment(dragOffset: leftDragOffset))
                    .gesture(
                        DragGesture(minimumDistance: 0)
                            .updating($leftDragOffset) { value, state, trans in
                                state = value.translation.width
                            }
                            .onEnded { value in
                                leftOffset = leftAdjustment(dragOffset: value.translation.width)
                            }
                    )
    
                Spacer()
    
                Image(systemName: "chevron.compact.right")
                    .frame(width: chevronWidth, height: 70)
                    .background(Color.blue)
                    .offset(x: -rightAdjustment(dragOffset: rightDragOffset))
                    .gesture(
                        DragGesture(minimumDistance: 0)
                            .updating($rightDragOffset) { value, state, trans in
                                state = value.translation.width
                            }
                            .onEnded { value in
                                rightOffset = rightAdjustment(dragOffset: value.translation.width)
                            }
                    )
    
            }
            .foregroundColor(.black)
            .font(.title3.weight(.semibold))
            .background {
                HStack(spacing: 0) {
                    Color.red
                    Color.cyan
                    Color.orange
                    Color.brown
                    Color.purple
                }
                .padding(.vertical, 5)
                .padding(.horizontal, chevronWidth)
                .background(.background)
                .mask {
                    Rectangle()
                        .padding(.leading, leftAdjustment(dragOffset: leftDragOffset))
                        .padding(.trailing, rightAdjustment(dragOffset: rightDragOffset))
                }
            }
            .frame(width: viewWidth)
            .background(.black)
        }
    }
    

    动画片

    • 1

相关问题

  • 将复制活动的序列号添加到 Blob

  • Packer 动态源重复工件

  • 选择每组连续 1 的行

  • 图形 API 调用列表 subscribedSkus 状态权限不足,但已授予权限

  • 根据列值创建单独的 DF 的函数

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    Vue 3:创建时出错“预期标识符但发现‘导入’”[重复]

    • 1 个回答
  • Marko Smith

    为什么这个简单而小的 Java 代码在所有 Graal JVM 上的运行速度都快 30 倍,但在任何 Oracle JVM 上却不行?

    • 1 个回答
  • Marko Smith

    具有指定基础类型但没有枚举器的“枚举类”的用途是什么?

    • 1 个回答
  • Marko Smith

    如何修复未手动导入的模块的 MODULE_NOT_FOUND 错误?

    • 6 个回答
  • Marko Smith

    `(表达式,左值) = 右值` 在 C 或 C++ 中是有效的赋值吗?为什么有些编译器会接受/拒绝它?

    • 3 个回答
  • Marko Smith

    何时应使用 std::inplace_vector 而不是 std::vector?

    • 3 个回答
  • Marko Smith

    在 C++ 中,一个不执行任何操作的空程序需要 204KB 的堆,但在 C 中则不需要

    • 1 个回答
  • Marko Smith

    PowerBI 目前与 BigQuery 不兼容:Simba 驱动程序与 Windows 更新有关

    • 2 个回答
  • Marko Smith

    AdMob:MobileAds.initialize() - 对于某些设备,“java.lang.Integer 无法转换为 java.lang.String”

    • 1 个回答
  • Marko Smith

    我正在尝试仅使用海龟随机和数学模块来制作吃豆人游戏

    • 1 个回答
  • Martin Hope
    Aleksandr Dubinsky 为什么 InetAddress 上的 switch 模式匹配会失败,并出现“未涵盖所有可能的输入值”? 2024-12-23 06:56:21 +0800 CST
  • Martin Hope
    Phillip Borge 为什么这个简单而小的 Java 代码在所有 Graal JVM 上的运行速度都快 30 倍,但在任何 Oracle JVM 上却不行? 2024-12-12 20:46:46 +0800 CST
  • Martin Hope
    Oodini 具有指定基础类型但没有枚举器的“枚举类”的用途是什么? 2024-12-12 06:27:11 +0800 CST
  • Martin Hope
    sleeptightAnsiC `(表达式,左值) = 右值` 在 C 或 C++ 中是有效的赋值吗?为什么有些编译器会接受/拒绝它? 2024-11-09 07:18:53 +0800 CST
  • Martin Hope
    The Mad Gamer 何时应使用 std::inplace_vector 而不是 std::vector? 2024-10-29 23:01:00 +0800 CST
  • Martin Hope
    Chad Feller 在 5.2 版中,bash 条件语句中的 [[ .. ]] 中的分号现在是可选的吗? 2024-10-21 05:50:33 +0800 CST
  • Martin Hope
    Wrench 为什么双破折号 (--) 会导致此 MariaDB 子句评估为 true? 2024-05-05 13:37:20 +0800 CST
  • Martin Hope
    Waket Zheng 为什么 `dict(id=1, **{'id': 2})` 有时会引发 `KeyError: 'id'` 而不是 TypeError? 2024-05-04 14:19:19 +0800 CST
  • Martin Hope
    user924 AdMob:MobileAds.initialize() - 对于某些设备,“java.lang.Integer 无法转换为 java.lang.String” 2024-03-20 03:12:31 +0800 CST
  • Martin Hope
    MarkB 为什么 GCC 生成有条件执行 SIMD 实现的代码? 2024-02-17 06:17:14 +0800 CST

热门标签

python javascript c++ c# java typescript sql reactjs html

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve