iOS 知识大全iOS14内容Widget

iOS14 Widget初体验

2020-09-23  本文已影响0人  RocketsChen

前言

iOS14发布已经有一段时间了,更新完之后最让我好奇的就是这个Widget功能。从用户使用到开发者开发上与iOS13有了很大的区别,用户可以更加个性化的去构建自己的桌面。

看完这篇博客,你可以大概的了解一些关于iOS14 Widget信息,和如何尝试编写一个简单的Widget小组件。

Widget代码演示部分可以直接跳至第三部分:iOS14 Widget的代码实现。

1:与iOS13 Widget区别

不同点

最直观的区别就是像官方演示视频展示的那样,可以直接在iPhone主屏幕进行组件的布局 如下图

image

iOS13-Widget


image

iOS14-Widget


image

除了显示上的区别外,代码的实现上也有不同

相同点

2:iOS14 Widget的特点

屏幕尺寸 - portrait 小部件-systemSmall 中型部件-systemMedium 大部件-systemLarge
414x896 pt (XR/XsMax/11/11ProMax) 169x169pt 360x169pt 360x379pt
375x812 pt (X/Xs/11 Pro) 155x155 pt 329x155 pt 329x345 pt
414x736 pt (6p/6sp/7p) 159x159 pt 348x159 pt 348x357 pt
375x667 pt (6/6s/7/8) 148x148 pt 321x148 pt 321x324 pt
320x568 pt (5/5s/SE) 141x141 pt 292x141 pt 292x311 pt

3:iOS14 Widget的代码实现

1:项目创建

1:Widget作为项目的一个组件,创建之前需要先创建一个iOS的项目。

2:项目创建成功后点击:File->New->Target添加Widget Extension Target 点击Next。


image

3:输入Widget组件名,取消勾选,点击Finish就可以了。Include Configuration Intent:是否支持用户配置。

image

4:如图可以看到默认生成的模板,默认预览组件的尺寸systemSmall。但是在真机上编译完可以看到Widget三个尺寸。你可以在预览方法中,添加systemMedium和systemLarge的预览。在Xcode12上最右边可视化界面直接模拟器运行和真机编译。

image
// MARK: - 预览
struct AdopterWidget_Previews: PreviewProvider {
    static var previews: some View {
        /// 小
        AdopterWidgetEntryView(entry: entry)
            .previewContext(WidgetPreviewContext(family: .systemSmall))
        
        /// 中
        AdopterWidgetEntryView(entry: entry)
            .previewContext(WidgetPreviewContext(family: .systemMedium))
        
        /// 大
        AdopterWidgetEntryView(entry: entry)
            .previewContext(WidgetPreviewContext(family: .systemLarge))
    }
}

5:熟悉的Hello World之后开始编写新的demo。


image

6:上面预览视图的工具

3:与主应用交互

根据官方文档的描述,点击Widget窗口唤起APP进行交互指定跳转支持两种方式:

if family == .systemSmall {  // 小
  VStack(alignment: .center, spacing: 20, content: {
      
      Text(entry.quotes.author)
          .font(.system(size: 16))
      Text(entry.quotes.content[0])
          .font(.system(size: 15))
          .foregroundColor(.black)
      Text("\(entry.quotes.date) at \(entry.quotes.place) ")
          .font(.system(size: 9))
          .foregroundColor(.gray)
  })
  .frame(maxWidth: /*@START_MENU_TOKEN@*/.infinity/*@END_MENU_TOKEN@*/, maxHeight: /*@START_MENU_TOKEN@*/.infinity/*@END_MENU_TOKEN@*/, alignment: /*@START_MENU_TOKEN@*/.center/*@END_MENU_TOKEN@*/).padding(16)
  .widgetURL(URL(string: "https://www.baidu.com/small"))

}
if family == .systemMedium { // 中
  
  VStack(alignment: .center, spacing: 8, content: {
      
      Text(entry.quotes.author)
          .font(.system(size: 18))
          .frame(height: 30, alignment: .top)
      
      Link(destination: URL(string: "https://www.baidu.com/medium/1")!) {
          Text(entry.quotes.content[0])
              .font(.system(size: 17))
              .foregroundColor(.black)
              .frame(maxWidth:.infinity, alignment: .leading)
      }

      Link(destination: URL(string: "https://www.baidu.com/medium/2")!) {
          Text(entry.quotes.content[1])
              .font(.system(size: 17))
              .foregroundColor(.black)
              .frame(maxWidth:.infinity, alignment: .leading)
      }
      
      Text("\(entry.quotes.date) at \(entry.quotes.place) ")
          .font(.system(size: 12))
          .foregroundColor(.gray)
          .frame(maxWidth:.infinity, alignment: .trailing)
          .frame(height: 20, alignment: .bottom)
  })
  .frame(maxWidth: .infinity, maxHeight: /*@START_MENU_TOKEN@*/.infinity/*@END_MENU_TOKEN@*/, alignment: .center).padding(16)
}

注!:systemSmall(小组件)只支持widgetURL,而systemMedium(中组件)和 systemLarge(大组件)则都支持。Link:更希望的是不同元素的点击响应。

- (void)scene:(UIScene *)scene openURLContexts:(NSSet<UIOpenURLContext *> *)URLContexts {
    /// 根据不同的URL回调做出响应
    NSLog(@"%@",URLContexts);
}

4:部分代码和方法注释

1:默认模板代码注释
func placeholder(in context: Self.Context) -> Self.Entry
func getSnapshot(in context: Self.Context, completion: @escaping (Self.Entry) -> Void)
func getTimeline(in context: Self.Context, completion: @escaping (Timeline<Self.Entry>) -> Void)

/// 这是更新时间5minute
let refreshDate = Calendar.current.date(byAdding: .minute, value: 5, to: currentDate)!

注!: 苹果原文档中有一段

Display Dynamic Dates
Because your widget extension is not always running, you can’t directly update your widget’s content. Instead, WidgetKit renders your widget’s view on your behalf and displays the result. However, some SwiftUI views let you display content that continues updating while your widget is visible.

由于您的窗口小部件扩展程序并不总是运行,因此您无法直接更新窗口小部件的内容。而是,WidgetKit代表您渲染窗口小部件的视图并显示结果。但是,某些SwiftUI视图可让您显示在可见窗口小部件时会继续更新的内容。

导致无法预测何时更新Widget。即使在上面设置了5分钟后再次获取时间轴本身进行更新,也无法保证iOS会同时更新视图。从而造成一定的Widget页面更新延迟。

/// 控件的所有已配置小部件重新加载时间线
/// 包含应用程序。
WidgetCenter.shared.reloadAllTimelines()
2:对于支持多个Widget和小、大、中页面数据布局的思考?

在查看苹果api之前我比较困惑的有两点?

上面通过默认方法的介绍,第二个问题已经解决了。

iOS14中Widget是支持通过创建一个扩展项目返回一个或多个小部件的,可以使您的应用提供多种小部件选择。并且在项目中视图通过WidgetFamily的枚举自定义自己想要的组件和布局。

public enum WidgetFamily : Int, RawRepresentable, CustomDebugStringConvertible, CustomStringConvertible {

    /// A small widget.
    case systemSmall

    /// A medium-sized widget.
    case systemMedium

    /// A large widget.
    case systemLarge
}
@main
struct SwiftWidgetsBundle: WidgetBundle {
    @WidgetBundleBuilder
    var body: some Widget {
        Widget1()
        Widget2()
        Widget3()
        Widget4()
        ...
    }
}

5:样式/演示

组件预览 组件和点击响应演示

6:项目地址

4:参考文献

5:总结

更新完iOS14 不管是在用户的使用上,还是组件的开发的过程中体验都更顺滑了。除了要切换成SwiftUI的开发时间成本来说,把项目的组件完成最新形式还是很吸引人的,开发上也很舒适。

新的Widget玩具感很强,感觉还有很多要更新和补充的东西。

最后文档中如果有理解有误的地方,欢迎反馈,我将及时更新和修正。

上一篇下一篇

猜你喜欢

热点阅读