SwiftUI分段控件视图刷新时选定的分段文本动画
在更改视图中的某些其他数据后刷新视图时,我正在体验分段控件的选定段中文本的以下动画: 这是一个错误/功能还是有办法消除这种行为? 这是重现效果的代码:SwiftUI分段控件视图刷新时选定的分段文本动画,swiftui,ios13,segmentedcontrol,Swiftui,Ios13,Segmentedcontrol,在更改视图中的某些其他数据后刷新视图时,我正在体验分段控件的选定段中文本的以下动画: 这是一个错误/功能还是有办法消除这种行为? 这是重现效果的代码: import SwiftUI struct ContentView: View { let colorNames1 = ["Red", "Green", "Blue"] @State private var color1 = 0 let colorNames2 = ["Yellow", "Purple", "Oran
import SwiftUI
struct ContentView: View {
let colorNames1 = ["Red", "Green", "Blue"]
@State private var color1 = 0
let colorNames2 = ["Yellow", "Purple", "Orange"]
@State private var color2 = 0
var body: some View {
VStack {
VStack {
Picker(selection: $color1, label: Text("Color")) {
ForEach(0..<3, id: \.self) { index in
Text(self.colorNames1[index]).tag(index)
}
}.pickerStyle(SegmentedPickerStyle())
Text("Color 1: \(color1)")
}
.padding()
VStack {
Picker(selection: $color2, label: Text("Color")) {
ForEach(0..<3, id: \.self) { index in
Text(self.colorNames2[index]).tag(index)
}
}.pickerStyle(SegmentedPickerStyle())
Text("Color 2: \(color2)")
}
.padding()
}
}
}
导入快捷界面
结构ContentView:View{
让colorNames1=[“红色”、“绿色”、“蓝色”]
@国家私有变量color1=0
让colorNames2=[“黄色”、“紫色”、“橙色”]
@国家私有变量2=0
var body:一些观点{
VStack{
VStack{
选择器(选择:$color1,标签:文本(“颜色”)){
ForEach(0..重新排列代码库…(这有助于SwiftUI仅“刷新”必要的视图)
导入快捷界面
结构ContentView:View{
让colorNames1=[“红色”、“绿色”、“蓝色”]
@国家私有变量color1=0
让colorNames2=[“黄色”、“紫色”、“橙色”]
@国家私有变量2=0
var body:一些观点{
VStack{
MyPicker(颜色名称:colorNames1,颜色:$color1)
.padding()
MyPicker(颜色名称:colorNames2,颜色:$color2)
.padding()
}
}
}
结构MyPicker:视图{
让颜色名称:[字符串]
@绑定变量颜色:Int
var body:一些观点{
VStack{
选择器(选择:$color,标签:Text(“color”)){
ForEach(0..我创建了一个自定义分段控件来解决此问题:
import SwiftUI
struct MyTextPreferenceKey: PreferenceKey {
typealias Value = [MyTextPreferenceData]
static var defaultValue: [MyTextPreferenceData] = []
static func reduce(value: inout [MyTextPreferenceData], nextValue: () -> [MyTextPreferenceData]) {
value.append(contentsOf: nextValue())
}
}
struct MyTextPreferenceData: Equatable {
let viewIndex: Int
let rect: CGRect
}
struct SegmentedControl : View {
@Binding var selectedIndex: Int
@Binding var rects: [CGRect]
@Binding var titles: [String]
var body: some View {
ZStack(alignment: .topLeading) {
SelectedView()
.frame(width: rects[selectedIndex].size.width - 4, height: rects[selectedIndex].size.height - 4)
.offset(x: rects[selectedIndex].minX + 2, y: rects[selectedIndex].minY + 2)
.animation(.easeInOut(duration: 0.5))
VStack {
self.addTitles()
}.onPreferenceChange(MyTextPreferenceKey.self) { preferences in
for p in preferences {
self.rects[p.viewIndex] = p.rect
}
}
}.background(Color(.red)).clipShape(Capsule()).coordinateSpace(name: "CustomSegmentedControl")
}
func totalSize() -> CGSize {
var totalSize: CGSize = .zero
for rect in rects {
totalSize.width += rect.width
totalSize.height = rect.height
}
return totalSize
}
func addTitles() -> some View {
HStack(alignment: .center, spacing: 8, content: {
ForEach(0..<titles.count) { index in
return SegmentView(selectedIndex: self.$selectedIndex, label: self.titles[index], index: index, isSelected: self.segmentIsSelected(selectedIndex: self.selectedIndex, segmentIndex: index))
}
})
}
func segmentIsSelected(selectedIndex: Int, segmentIndex: Int) -> Binding<Bool> {
return Binding(get: {
return selectedIndex == segmentIndex
}) { (value) in }
}
}
struct SegmentView: View {
@Binding var selectedIndex: Int
let label: String
let index: Int
@Binding var isSelected: Bool
var body: some View {
Text(label)
.padding(.vertical, 6)
.padding(.horizontal, 10)
.foregroundColor(Color(.label))
.background(MyPreferenceViewSetter(index: index)).onTapGesture {
self.selectedIndex = self.index
}
}
}
struct MyPreferenceViewSetter: View {
let index: Int
var body: some View {
GeometryReader { geometry in
Rectangle()
.fill(Color.clear)
.preference(key: MyTextPreferenceKey.self,
value: [MyTextPreferenceData(viewIndex: self.index, rect: geometry.frame(in: .named("CustomSegmentedControl")))])
}
}
}
struct SelectedView: View {
var body: some View {
Capsule()
.fill(Color(.systemBackground))
.edgesIgnoringSafeArea(.horizontal)
}
}
导入快捷界面
结构MyTextPreferenceKey:PreferenceKey{
typealias值=[MyTextPreferenceData]
静态变量defaultValue:[MyTextPreferenceData]=[]
静态函数reduce(值:inout[MyTextPreferenceData],nextValue:()->[MyTextPreferenceData]){
append(contentsOf:nextValue())
}
}
结构MyTextPreferenceData:Equalable{
让viewIndex:Int
let rect:CGRect
}
结构分段控件:视图{
@绑定变量selectedIndex:Int
@绑定变量rects:[CGRect]
@绑定变量标题:[字符串]
var body:一些观点{
ZStack(对齐:。顶部引导){
SelectedView()
.frame(宽度:rects[selectedIndex].size.width-4,高度:rects[selectedIndex].size.height-4)
.offset(x:rects[selectedIndex].minX+2,y:rects[selectedIndex].minY+2)
.animation(.easeInOut(持续时间:0.5))
VStack{
self.addTitles()
}.onPreferenceChange(MyTextPreferenceKey.self){中的首选项
对于首选项中的p{
self.rects[p.viewIndex]=p.rect
}
}
}.background(颜色(.red)).clipShape(胶囊()).coordinateSpace(名称:“CustomSegmentedControl”)
}
func totalSize()->CGSize{
变量totalSize:CGSize=.0
对于矩形中的矩形{
totalSize.width+=矩形宽度
totalSize.height=矩形高度
}
返回总大小
}
func addTitles()->一些视图{
HStack(对齐:。中心,间距:8,内容:{
ForEach(0..Binding{
返回绑定(获取:{
返回selectedIndex==分段索引
}){(值)in}
}
}
结构段视图:视图{
@绑定变量selectedIndex:Int
让标签:字符串
let索引:Int
@绑定变量:Bool
var body:一些观点{
文本(标签)
.padding(.vertical,6)
.padding(.卧式,10)
.foregroundColor(颜色(.label))
.background(MyPreferenceViewSetter(索引:index)).ontaps{
self.selectedIndex=self.index
}
}
}
结构MyPreferenceViewSetter:视图{
let索引:Int
var body:一些观点{
GeometryReader{中的几何体
矩形()
.填充(颜色.透明)
.preference(键:MyTextPreferenceKey.self,
值:[MyTextPreferenceData(viewIndex:self.index,rect:geometry.frame(in:.named(“CustomSegmentedControl”))]))
}
}
}
struct SelectedView:View{
var body:一些观点{
胶囊()
.fill(颜色(.systemBackground))
.边缘识别安全区域(.水平)
}
}
是的,值得向苹果提交反馈。我没有使用SwiftUI(只是将小部件放在情节提要中)当我更新片段中的文本时,也会看到同样的问题。我在片段标题中显示了一些项目,因此它们需要定期更新。我还没有找到解决方案。谢谢。您的解决方法解决了上述问题,因此我将接受答案。但是,我实际的问题是将核心数据对象作为Observ传递的视图ableObject和分段控件用于设置该对象的属性;因此,如果可能的话,我需要找到一种方法使这种方法在那里工作。尽管如此,我还是提交了反馈,希望苹果能解决这个问题。
import SwiftUI
struct MyTextPreferenceKey: PreferenceKey {
typealias Value = [MyTextPreferenceData]
static var defaultValue: [MyTextPreferenceData] = []
static func reduce(value: inout [MyTextPreferenceData], nextValue: () -> [MyTextPreferenceData]) {
value.append(contentsOf: nextValue())
}
}
struct MyTextPreferenceData: Equatable {
let viewIndex: Int
let rect: CGRect
}
struct SegmentedControl : View {
@Binding var selectedIndex: Int
@Binding var rects: [CGRect]
@Binding var titles: [String]
var body: some View {
ZStack(alignment: .topLeading) {
SelectedView()
.frame(width: rects[selectedIndex].size.width - 4, height: rects[selectedIndex].size.height - 4)
.offset(x: rects[selectedIndex].minX + 2, y: rects[selectedIndex].minY + 2)
.animation(.easeInOut(duration: 0.5))
VStack {
self.addTitles()
}.onPreferenceChange(MyTextPreferenceKey.self) { preferences in
for p in preferences {
self.rects[p.viewIndex] = p.rect
}
}
}.background(Color(.red)).clipShape(Capsule()).coordinateSpace(name: "CustomSegmentedControl")
}
func totalSize() -> CGSize {
var totalSize: CGSize = .zero
for rect in rects {
totalSize.width += rect.width
totalSize.height = rect.height
}
return totalSize
}
func addTitles() -> some View {
HStack(alignment: .center, spacing: 8, content: {
ForEach(0..<titles.count) { index in
return SegmentView(selectedIndex: self.$selectedIndex, label: self.titles[index], index: index, isSelected: self.segmentIsSelected(selectedIndex: self.selectedIndex, segmentIndex: index))
}
})
}
func segmentIsSelected(selectedIndex: Int, segmentIndex: Int) -> Binding<Bool> {
return Binding(get: {
return selectedIndex == segmentIndex
}) { (value) in }
}
}
struct SegmentView: View {
@Binding var selectedIndex: Int
let label: String
let index: Int
@Binding var isSelected: Bool
var body: some View {
Text(label)
.padding(.vertical, 6)
.padding(.horizontal, 10)
.foregroundColor(Color(.label))
.background(MyPreferenceViewSetter(index: index)).onTapGesture {
self.selectedIndex = self.index
}
}
}
struct MyPreferenceViewSetter: View {
let index: Int
var body: some View {
GeometryReader { geometry in
Rectangle()
.fill(Color.clear)
.preference(key: MyTextPreferenceKey.self,
value: [MyTextPreferenceData(viewIndex: self.index, rect: geometry.frame(in: .named("CustomSegmentedControl")))])
}
}
}
struct SelectedView: View {
var body: some View {
Capsule()
.fill(Color(.systemBackground))
.edgesIgnoringSafeArea(.horizontal)
}
}