如何用纯代码构建一个 Widget(2014)

2023-11-05 13:58
文章标签 代码 构建 2014 widget 用纯

本文主要是介绍如何用纯代码构建一个 Widget(2014),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

随着iOS8的发布 各种iPhone的新玩法出现了 其中最引人关注的就是 today extension (也叫做widget) 这个在android上存在了多年的小玩意 也是iPhone一直被人诟病的东西 终于能用上了

网上有很多相关的文章教你如何编写一个简单的widget 但是却没有一篇适合我们这种纯代码的拥趸(也有很多人说应该放弃纯代码 改用Storyboard了) 那么接下来我就说说 如何用纯代码的方式来构建一个widget

准备

首先 你得有个正常的app项目(这是必须的 extension必须依附于某个app中 当然 不这样 你也无法单独安装某个widget)

打开项目工程 选择新建一个target 在 Application Extension 中选择 today exntension 然后填入名字 确认即可

这时你的项目里多个一个target 同时也多了下面

接下来 删掉这个讨厌的 MainInterface.storyboard 然后修改plist文件中的 NSExtension 字段

  • 删掉 NSExtensionMainStoryboard 字段
  • 添加 NSExtensionPrincipalClass 字段 并设为 TodayViewController (你也可以指定其他的ViewController)

修改完以后 Widget就可以开始编译运行了

运行

关于调试Widget 我推荐使用模拟器而不用真机 因为在研究过程中我发现真机调试的效果非常差 经常提示无法连接到手机(也有可能是5S的性能够不?) 导致无法正常的debug 或者无法reinstall 而模拟器则好点(至少能顺利的打印出log) 但是每次修改好代码以后 最好都先退出模拟器 再重新编译运行 如果你退出重新运行时提示下面这个错误 不用怕 多运行两次就ok了

Command+R 编译运行 会弹出提示框让你选择宿主app 就选择默认的today就好了

如无意外 模拟器启动时会自动打开today 并显示你的widget

是不是发现什么都没有? 如果用Storyboard构建的Widget 会默认有个 Hello 可我们弄出来的Widget 却啥都没有 连高度都没有

那么问题来了…

修改

首先 我们设置一下widget的高度 并添加一个contentView和一个button(注意 这里我使用的是 Masonry 来完成autolayout 相关信息可见我的上一篇文章: Masonry介绍与使用实践(快速上手Autolayout) )


@interface TodayViewController () <NCWidgetProviding>

@property (strong, nonatomic) UIView *contentView;
@property (nonatomic, strong) UIButton *btnTest;

@end


- (void)viewDidLoad {
    [super viewDidLoad];
    
    //使用preferredContentSize设置大小 且只用设置高度就好了
    self.preferredContentSize = CGSizeMake(0, 200);
    
    __weak __typeof(&*self)ws = self;
    
    self.contentView = [UIView new];
    self.contentView.backgroundColor = [UIColor whiteColor];
    [self.view addSubview:self.contentView];
    
    [self.contentView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.edges.equalTo(ws.view);
    }];
    
    self.btnTest = [UIButton buttonWithType:UIButtonTypeCustom];
    [self.btnTest setTitle:[[NSDate date] description] forState:UIControlStateNormal];
    self.btnTest.backgroundColor = [UIColor redColor];
    [self.btnTest addTarget:self action:@selector(actionTest) forControlEvents:UIControlEventTouchUpInside];
    
    [self.contentView addSubview:self.btnTest];
    
    [self.btnTest mas_makeConstraints:^(MASConstraintMaker *make) {
        make.center.equalTo(ws.contentView);
        make.size.mas_equalTo(CGSizeMake(300, 40));
    }];
}

运行一下 看看效果

控件是出来了 可是没有如我们的意 旁边还空了一块 原来widget默认会有一个inset 那么如何取消这个inset呢? 重载如下方法即可

- (UIEdgeInsets)widgetMarginInsetsForProposedMarginInsets:(UIEdgeInsets)defaultMarginInsets
{
    return UIEdgeInsetsZero;
}

修改完以后您再看

一个Widget的模子就这样构建完成了

进阶

接下来 我们给button加个点击事件 用来改变widget的大小

- (void) actionTest
{
    self.preferredContentSize = CGSizeMake(0, self.contentView.frame.size.height>250?200:300);
}

测试发现效果”还可以” 为什么仅仅是”还可以”呢 可以看到当size变化时 其他区域其实是有个动态变化的效果 但是我们的widget的变化是立即的 所以看上去不那么流畅(storyboard里就不存在这个问题了 因为使用了autolayout)

那么我们可不可以也使用autolayout 而不设置这个 preferredContentSize 呢? 答案是可以的

首先修改viewDidLoad的代码

- (void)viewDidLoad {
    [super viewDidLoad];
    
    //去掉这一步
    //self.preferredContentSize = CGSizeMake(0, 200);
    
    __weak __typeof(&*self)ws = self;
    
    self.contentView = [UIView new];
    self.contentView.backgroundColor = [UIColor whiteColor];
    [self.view addSubview:self.contentView];
    
    [self.contentView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.edges.equalTo(ws.view);
        //设置内部view的高度(一定要设置高优先级 不然会有冲突)
        make.height.mas_equalTo(@200).priorityHigh();
    }];
    
    ...
    ...
    ...
    
}

然后修改按钮的动作

- (void) actionTest
{
    //去掉这一步
    //self.preferredContentSize = CGSizeMake(0, self.contentView.frame.size.height>250?200:300);
    
    //更新autolayout
    [self.contentView mas_updateConstraints:^(MASConstraintMaker *make) {
        make.height.mas_equalTo(@(self.contentView.frame.size.height>250?200:300)).priorityHigh();
    }];
}

试着运行一下 你会发现世界变得很美丽了

至此 发挥你的想象吧 you can do whatever you want!

小结

所有的准备工作都已经做完了 编写一个Widget也变得很简单 你可以像写任何一个ViewController一样来写Widget 而纯代码的方式我相信会让很多人更得心应手

这篇关于如何用纯代码构建一个 Widget(2014)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


原文地址:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.chinasem.cn/article/350297

相关文章

IIS 7.0 及更高版本中的 FTP 状态代码

《IIS7.0及更高版本中的FTP状态代码》本文介绍IIS7.0中的FTP状态代码,方便大家在使用iis中发现ftp的问题... 简介尝试使用 FTP 访问运行 Internet Information Services (IIS) 7.0 或更高版本的服务器上的内容时,IIS 将返回指示响应状态的数字代

MySQL 添加索引5种方式示例详解(实用sql代码)

《MySQL添加索引5种方式示例详解(实用sql代码)》在MySQL数据库中添加索引可以帮助提高查询性能,尤其是在数据量大的表中,下面给大家分享MySQL添加索引5种方式示例详解(实用sql代码),... 在mysql数据库中添加索引可以帮助提高查询性能,尤其是在数据量大的表中。索引可以在创建表时定义,也可

使用C#删除Excel表格中的重复行数据的代码详解

《使用C#删除Excel表格中的重复行数据的代码详解》重复行是指在Excel表格中完全相同的多行数据,删除这些重复行至关重要,因为它们不仅会干扰数据分析,还可能导致错误的决策和结论,所以本文给大家介绍... 目录简介使用工具C# 删除Excel工作表中的重复行语法工作原理实现代码C# 删除指定Excel单元

Python实现一键PDF转Word(附完整代码及详细步骤)

《Python实现一键PDF转Word(附完整代码及详细步骤)》pdf2docx是一个基于Python的第三方库,专门用于将PDF文件转换为可编辑的Word文档,下面我们就来看看如何通过pdf2doc... 目录引言:为什么需要PDF转Word一、pdf2docx介绍1. pdf2docx 是什么2. by

Spring Security介绍及配置实现代码

《SpringSecurity介绍及配置实现代码》SpringSecurity是一个功能强大的Java安全框架,它提供了全面的安全认证(Authentication)和授权(Authorizatio... 目录简介Spring Security配置配置实现代码简介Spring Security是一个功能强

通过cmd获取网卡速率的代码

《通过cmd获取网卡速率的代码》今天从群里看到通过bat获取网卡速率两段代码,感觉还不错,学习bat的朋友可以参考一下... 1、本机有线网卡支持的最高速度:%v%@echo off & setlocal enabledelayedexpansionecho 代码开始echo 65001编码获取: >

Java集成Onlyoffice的示例代码及场景分析

《Java集成Onlyoffice的示例代码及场景分析》:本文主要介绍Java集成Onlyoffice的示例代码及场景分析,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要... 需求场景:实现文档的在线编辑,团队协作总结:两个接口 + 前端页面 + 配置项接口1:一个接口,将o

SpringBoot实现Kafka动态反序列化的完整代码

《SpringBoot实现Kafka动态反序列化的完整代码》在分布式系统中,Kafka作为高吞吐量的消息队列,常常需要处理来自不同主题(Topic)的异构数据,不同的业务场景可能要求对同一消费者组内的... 目录引言一、问题背景1.1 动态反序列化的需求1.2 常见问题二、动态反序列化的核心方案2.1 ht

IDEA实现回退提交的git代码(四种常见场景)

《IDEA实现回退提交的git代码(四种常见场景)》:本文主要介绍IDEA实现回退提交的git代码(四种常见场景),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1.已提交commit,还未push到远端(Undo Commit)2.已提交commit并push到

Kotlin Compose Button 实现长按监听并实现动画效果(完整代码)

《KotlinComposeButton实现长按监听并实现动画效果(完整代码)》想要实现长按按钮开始录音,松开发送的功能,因此为了实现这些功能就需要自己写一个Button来解决问题,下面小编给大... 目录Button 实现原理1. Surface 的作用(关键)2. InteractionSource3.