当前位置: 首页 > news >正文

山西网站建设网站企业管理平台app

山西网站建设网站,企业管理平台app,虚拟资源交易商城wordpress,上海公司车辆怎么查询违章一、前言 在 Dribbble 上找到的设计的 SwiftUI 实现时,可以尝试通过一些酷炫的筛选器扩展该项目以缩小结果列表。筛选视图将由两个独立的筛选选项组成,两者都有一些可选项可供选择。但是,在使用 UIKit 时,总是将这种类型的视图实…

一、前言

  • 在 Dribbble 上找到的设计的 SwiftUI 实现时,可以尝试通过一些酷炫的筛选器扩展该项目以缩小结果列表。筛选视图将由两个独立的筛选选项组成,两者都有一些可选项可供选择。但是,在使用 UIKit 时,总是将这种类型的视图实现为具有特定 UICollectionViewFlowLayout 的 UICollectionView。
  • 那么,在 SwiftUI 中该如何实现呢?现在来看看使用 SwiftUI 创建灵活选择器的实现。

二、可选择协议

  • 选择器的最重要部分是,可以通过该视图组件选择一些所需的选项。因此,首先创建一个 Selectable 协议。所有符合该协议的对象必须实现两个属性:displayedName(在选择器中显示的名称)和 isSelected(一个布尔值,指示特定选项是否已选择)。
  • 此外,为了能够通过映射字符串值数组创建 Selectable 对象,实现 Selectable 的对象必须提供带 displayedName 作为参数的自定义初始化。Identifiable 和 Hashable 协议确保我们可以轻松创建具有 ForEach 循环的 SwiftUI 视图。此外,符合 Selectable 协议的所有对象都将实现存储 UUID 值的常量 id。
  • 故意省略符合 Selectable 协议的对象的实现,因为这是显而易见的。核心代码如下:
protocol Selectable: Identifiable, Hashable {var displayedName: String { get }var isSelected: Bool { get set }init(displayedName: String)
}

三、自定义化

  • 不仅是创建灵活的选择器的实现,还要尽量使其可自定义。因此,将使用符合 Selectable 协议的泛型类型 T 创建 FlexiblePicker,这样,以后更容易重用该组件,因为它将是独立于类型的。
  • 在实现选择器本身之前,可以列出所有可自定义属性。接下来,创建用于计算特定字符串值的宽度和高度的字符串扩展。由于允许更改字体大小和权重,因此先前提到的两个扩展都以由灵活选择器使用的 UIFont 作为参数。
extension String {func getWidth(with font: UIFont) -> CGFloat {let fontAttributes = [NSAttributedString.Key.font: font]let size = self.size(withAttributes: fontAttributes)return size.width}func getHeight(with font: UIFont) -> CGFloat {let fontAttributes = [NSAttributedString.Key.font: font]let size = self.size(withAttributes: fontAttributes)return size.height}
}
  • 由于字符串扩展用于计算给定字符串的大小,因此需要将所有 UIFont 权重转换为 SwiftUI 等效项。这就是为什么需要引入一个 FontWeight 枚举,其中包含以 UIFont 权重命名的所有可能情况。
  • 此外,该枚举有两个属性,一个返回 UIFont 权重,另一个返回 SwiftUI Font 权重。通过这种方式,只需向 FlexiblePicker 提供 FontWeight 枚举的特定情况。
enum FontWeight {case light// the rest of possible casesvar swiftUIFontWeight: Font.Weight {switch self {case .light:            return .light// switching through the rest of possible cases }}var uiFontWeight: UIFont.Weight {switch self {case .light:            return .light// switching through the rest of possible cases }}
}

四、FlexiblePicker 逻辑

  • 之后,终于准备好开始编写 FlexiblePicker 的实现了。首先,需要一个函数来计算并返回输入数据的所有宽度,通过将所有输入值映射到元组中,其中包含输入值和自身的宽度来完成。
  • 在映射中,使用 reduce 函数来总结与给定输入值相关联的所有宽度(文本宽度、边框宽度、文本填充和间距)。
private func calculateWidths(for data: [T]) -> [(value: T, width: CGFloat)] {return data.map { selectableType -> (T, CGFloat) inlet font = UIFont.systemFont(ofSize: fontSize, weight: fontWeight.uiFontWeight)let textWidth = selectableType.displayedName.getWidth(with: font)let width = [textPadding, textPadding, borderWidth, borderWidth, spacing].reduce(textWidth, +)return (selectableType, width)}
}
  • 现在,计算宽度的函数已经准备好,可以遍历所有输入数据并将它们分成单独的数组,每个数组包含能够适应同一 HStack 中的项目的项目。
  • 逻辑很简单,需要有两个数组:
    • singleLineResult 数组——负责存储适合特定行的项目;
    • allLinesResult 数组——负责存储所有项目数组(每个数组都等同于一行项目)。
  • 首先,检查从 HStack 行宽中减去项宽的结果是否大于 0:
    • 如果满足条件,将当前项附加到 singleLineResult 中,更新可用的 HStack 行宽,并继续到下一个元素。
    • 如果结果小于 0,这意味着无法将下一个元素放入给定行中,因此将 singleLineResult 附加到 allLinesResult 中,将 singleLineResult 设置为仅由当前元素组成的数组(不能适应上一行的元素),并通过减去当前项的宽度来更新 HStack 的行宽。
  • 在遍历所有元素之后,必须处理特定的边缘情况。singleLineResult 可能不会为空,也不会附加到 allLinesResult 中,因为只在减去项目宽度的结果小于 0 时附加 singleLineResult。在这种情况下,我们必须检查 singleLineResult 是否为空。如果为真,返回 allLinesResult,如果不为真,必须首先附加 singleLineResult,然后返回 allLinesResult。
private func divideDataIntoLines(lineWidth: CGFloat) -> [[T]] {let data = calculateWidths(for: inputData)var singleLineWidth = lineWidthvar allLinesResult = [[T]]()var singleLineResult = [T]()var partialWidthResult: CGFloat = 0data.forEach { (selectableType, width) inpartialWidthResult = singleLineWidth - widthif partialWidthResult > 0 {singleLineResult.append(selectableType)singleLineWidth -= width} else {allLinesResult.append(singleLineResult)singleLineResult = [selectableType]singleLineWidth = lineWidth - width}}guard !singleLineResult.isEmpty else { return allLinesResult }allLinesResult.append(singleLineResult)return allLinesResult
}
  • 最后但并非最不重要的是,必须计算 VStack 的高度,以使 SwiftUI 更容易解释我们的视图组件,VStack 的高度是根据两个值计算的:
    • 输入数据中任何项目的高度(类似于宽度的计算,通过使用 reduce 函数,总结与项目相关的所有高度);
    • 将显示在 VStack 中的行数。
private func calculateVStackHeight(width: CGFloat) -> CGFloat {let data = divideDataIntoLines(lineWidth: width)let font = UIFont.systemFont(ofSize: fontSize, weight: fontWeight.uiFontWeight)guard let textHeight = data.first?.first?.displayedName.getHeight(with: font) else { return 16 }let result = [textPadding, textPadding, borderWidth, borderWidth, spacing].reduce(textHeight, +)return result * CGFloat(data.count)
}
  • 将这两个数字相乘的结果将是我们的 VStack 的高度。

五、FlexiblePicker 视图

  • 最后,当所有逻辑准备好后,需要实现一个视图主体。如之前所提到的,视图将使用嵌套的 ForEach 循环创建。需要记住的是,ForEach 循环要求迭代的集合中的每个元素必须符合 Identifiable 协议,或者应该具有唯一的标识符。这就是为什么将分隔行的结果映射到元组中,其中包含每行和 UUID 值。
  • 由于如此,可以向 ForEach 循环提供 id 参数。另一点需要记住的是,ForEach 循环期望获得一些 View 作为返回值。如果只插入另一个 ForEach 循环,将在视图的适当功能性方面遇到问题,因为 ForEach 不是一种 View。这就是为什么首先将整个 ForEach 循环包装在 HStack 中,然后再包装在 Group 中,以确保编译器可以正确解释一切。
var body: some View {GeometryReader { geo inVStack(alignment: alignment, spacing: spacing) {ForEach(divideDataIntoLines(lineWidth: geo.size.width).map { (data: $0, id: UUID()) }, id: \.id) { dataArray inGroup {HStack(spacing: spacing) {ForEach(dataArray.data, id: \.id) { data inButton(action: { updateSelectedData(with: data)}) {Text(data.displayedName).lineLimit(1).foregroundColor(textColor).font(.system(size: fontSize, weight: fontWeight.swiftUIFontWeight)).padding(textPadding)}.background(data.isSelected? selectedColor.opacity(0.5): notSelectedColor.opacity(0.5)).cornerRadius(10).disabled(!isSelectable).overlay(RoundedRectangle(cornerRadius: 10).stroke(borderColor, lineWidth: borderWidth))}}}}}.frame(width: geo.size.width, height: calculateVStackHeight(width: geo.size.width))}}
}
  • 几乎所有都已经完成,只需添加一个函数来处理与按钮的用户交互,该函数只需切换特定数据的 isSelected 属性:
private func updateSelectedData(with data: T) {guard let index = inputData.indices.first(where: { inputData[$0] == data }) else { return }inputData[index].isSelected.toggle()
}
  • 其余的代码很简单,主要是配置所有属性,如字体、颜色或边框。此外,在 VStack 的底部,我们设置一个 frame,其中宽度取自 GeometryReader,高度则由先前创建的函数计算。

在这里插入图片描述

  • 现在 FlexiblePicker 已经完成,便可以使用了。

六、总结

  • 本文完整使用 SwiftUI 构建一个灵活的选择器(FlexiblePicker),用于选择多个选项。
  • 首先创建了一个 Selectable 协议,使得选择的选项对象需要实现 displayedName 和 isSelected 属性。
  • 然后,详细介绍了实现该选择器的逻辑,包括如何处理选项的布局、宽度和高度,以及如何处理用户与按钮的交互。
  • 最后,提供了一个简单的视图实现,可以在 SwiftUI 中使用该选择器,这个选择器可用于创建各种交互式选择界面。
http://www.yayakq.cn/news/358598/

相关文章:

  • 网站建设的 文献综述统计局门户网站建设目标
  • 品牌型网站建设解决方案有没有专门做布料的网站
  • 建设商城网站的书籍钱软文是指什么
  • 教学网站建设上海专业网站建设精英
  • 成立网站是不是需要先成立公司网站改备案
  • 网站设计代做如何利用网站来提升企业形象
  • 去生活服务性的网站做php好吗天津智能网站建设价位
  • 那个网站是做房产中介的wordpress 老版本
  • 北京网站ui设计公司推广网络营销外包
  • 创建网站根目录安装wordpress建站程序
  • 登录深圳住房和建设局网站新乡网站建设哪家优惠
  • 网批做衣服的网站庐山市星子网
  • 域名网络的解析网站外贸网站建设智能建站
  • 单位网站建设内容个人简历模板word格式免费下载
  • 网上做实验的网站惠州城市建设建筑网站
  • 做网站市场价格南宁排名seo公司
  • 河南省建设厅证件证件查询网站诸城建设局网站
  • 佛山网站建设公司有哪wordpress 歌词
  • 网站开发怎么对接客户网页设计软件dw怎么安装
  • 网站开发如何避免浏览器缓存的影响flas网站开发工具
  • 怎么写公司网站的文案网站开发与兼容模式
  • 静态网站中切换图片怎么做科技与狠活是什么意思
  • 济宁网站建设培训班全球十大营销策划公司
  • 网站开发人员 生活体育健身网站建设
  • 做电脑网站手机能显示不出来怎么办啊网站建设运营费用预算
  • 网站建设费用选择网络专业嘟嘟嘟在线观看播放免费
  • 成为网站有哪些网址?wordpress 评论ajax
  • 汕头网站设计制作公司广州seo排名优化
  • 网站功能需求表怎么用asp.net做网站
  • 做服装有哪些好的网站有哪些精准引流推广