iOS14 Widget小组件知识点集锦

近期在做Widget小组件相关的开发,于是整理和记录在iOS14 Widget小组件开发过程中用到的知识点,本文将持续更新…

1、与APP数据同步

首先你得有个AppGroup,添加AppGroup,选择Target,点击Signing & Capability,再点击+Capability,找到AppGroup并双击。然后在AppGroups列表找到要使用ID,如果没有的话可以通过+新增即可。

NSUserDefault方式:

//OC
NSUserDefault *store = [[NSUserDefaults alloc] initWithSuiteName:@"group.yourgroupid"];
[store setObject:@"yourvalue" forKey:@"yourkey"];
[store synchronize];

//Swift

let store = UserDefaults(suiteName: "group.yourgroupid")
store.setValue(@"yourvalue", forKey: @"yourkey")
store.synchronize()

let store = UserDefaults(suiteName: "group.yourgroupid")
let obj = store.value(forKey: "yourkey")
if obj == nil {

} else {

} 

NSFileManager文件方式:

NSURL *yourFileURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.yourgroupid"];
yourFileURL = [yourFileURL URLByAppendingPathComponent:@"your_file_name"];
//TODO: 拿到file url后就可以做你想做的事了

2、强制刷新Widget

当需要触发刷新Widget时,可通过WidgetCenter.shared.reloadAllTimelines()刷新全部,或者通过kind string刷新某一个WidgetCenter.shared.reloadTimelines(ofKind: “your_kind_string”)

WidgetKit只存在于Swift中,所以使用Objective-C的需要引入Swift混编,通过OC调用Swift来刷新Widget,至于OC和Swift混编的相关知识请各位自行查找。

import Foundation
import WidgetKit

public class MyWidget: NSObject {
    
    @objc
    public func reloadWidget() {
        if #available(iOS 14.0, *) {
            WidgetCenter.shared.reloadAllTimelines()
        } else {
            // Fallback on earlier versions
        };
    }
}

3、显示一张图片

针对不同尺寸的Widget进行处理,通过添加Image控件进行显示。

struct PPPasswordWidgetEntryView : View {
    var entry: Provider.Entry
    //针对不同尺寸的 Widget 设置不同的 View
    @Environment(\.widgetFamily) var family // 尺寸环境变量
    
    var body: some View {
        switch family {
        case.systemSmall:
            Image.init("AppBgImage")
                            .resizable()
                            .frame(minWidth: 141, maxWidth: 200, minHeight: 141, maxHeight: 200, alignment: .center)
                            .scaledToFit()
                            .edgesIgnoringSafeArea(.all)
        case.systemMedium:
            Image.init("AppBgImage")
                            .resizable()
                            .frame(minWidth: 141, maxWidth: 200, minHeight: 141, maxHeight: 200, alignment: .center)
                            .scaledToFit()
                            .edgesIgnoringSafeArea(.all)
        default:
            Image.init("AppBgImage")
                            .resizable()
                            .frame(minWidth: 141, maxWidth: 400, minHeight: 141, maxHeight: 400, alignment: .center)
                            .scaledToFit()
                            .edgesIgnoringSafeArea(.all)
        }
        
    }
}

4、显示图片+文字

通过设置VStack的background来实现背景图片,通过在VStack中添加Text实现文本显示。

struct GYWidgetEntryView : View {
    var entry: Provider.Entry
    var body: some View {
        let themeBgName = entry.themeBgName//主题背景图片
        let textColor = entry.textColor//要显示文字内容
        
        GeometryReader{ geo in
            VStack {
                Text(entry.content)
                    .font(.system(size: 24))
                    .padding(12)
                    .minimumScaleFactor(0.2)
                    .foregroundColor(textColor)
            }.frame(width: geo.size.width, height: geo.size.height)
            .background(Image(themeBgName)
                            .resizable()
                            .scaledToFill())
            .padding(0)
        }
    }
}

5、文字自适应

Text(entry.content)
    .font(.system(size: 24))
    .padding(12)
    .minimumScaleFactor(0.2)
    .foregroundColor(textColor)

5、日期转字符串

//日期 -> 字符串
func date2String(date:Date, dateFormat:String = "yyyy-MM-dd HH:mm:ss") -> String {
    let formatter = DateFormatter()
    formatter.locale = Locale.init(identifier: "zh_CN")
    formatter.dateFormat = dateFormat
    let date = formatter.string(from: date)
    return date
}

6、增加多组Widget

删除原Widget的@main声明,增加WidgetBundle

@main
struct Widgets: WidgetBundle {
    @WidgetBundleBuilder
    var body: some Widget {
        BJXX2Widget();
        BJXXWidget()
    }
}

7、设置只显示小组件,中号和大号组件不显示

通过supportedFamilies方法进行设置,参数为支持的WidgetFamily数组,共包含了.systemSmall、.systemMedium、.systemLarge。

struct BJXX2Widget: Widget {
    let kind: String = "BJXX2Widget"//北京限行日历小组件

    var body: some WidgetConfiguration {
        StaticConfiguration(kind: kind, provider: Provider()) { entry in
            BJXX2WidgetEntryView(entry: entry)
        }
        .configurationDisplayName("一周限行")
        .supportedFamilies([.systemSmall])
        .description("限行号码一目了然")
    }
}

8、自定义View

如何实现尾号限行日历小组件中一天的布局呢?自定义DayItemView,通过VStack包裹日期和限行尾号即可。

struct DayItemView : View {
    let day: String
    let number: String

    init(day: String, number:String) {
        self.day = day
        self.number = number
    }
    
    var body: some View {
        VStack {
            Spacer()
            Text(day)//那一天,例如:16
                .font(.system(size: 12))
                
            Text(number)//限行尾号,例如2和7
                .font(.system(size: 9)).foregroundColor(.gray)
                
            Spacer()
        }
        .frame(width: 32, height: 32, alignment: .center)
    }
}

8、审核相关

小组件内容应该丰富的个性化的动态的,避免提供静态内容。要不很容易就审核人员4.4拒绝了。

如果你的小组件不包含Siri快捷键指令,请在提交审核时在备注中写上:不包含Siri快捷指令。如不不填写的话可能会被打回补充信息,询问是否包含Siri快捷键指令或如何操作等等,之前我增加Widget后首次提交审核审就是被这样打回的。

未完待续…

打赏

尊重原创内容,转载请注明出处
本文链接地址: https://www.awnlab.com/archives/464

为您推荐

发表评论

邮箱地址不会被公开。 必填项已用*标注