iOS 练习项目 Landmarks (五):UISwitch 切换展示数据

iOS 练习项目 Landmarks (五):UISwitch 切换展示数据

iOS 练习项目 Landmarks (五):UISwitch 切换展示数据

引入 Lookin

新建一个Podfile:

shell 复制代码
source 'https://xxx.git'
platform :ios, '17.5'
use_frameworks!
target 'Landmarks' do
  pod 'LookinServer', '1.2.2', :configurations => ['Debug']
end

从 source 中引入 LookinServer,版本为 1.2.2。

命令行输入:

shell 复制代码
pod install

编译报错:

复制代码
Sandbox:rsync.sanba deny(1) file-write-create xxx

解决方法:Build Settings-Build Options-User Script Sandboxing 改为 NO。

User Script Sandboxing是一种安全策略,它通过创建一个受限制的执行环境来限制用户脚本的访问权限和资源使用。其主要目的是防止恶意代码或未经授权的用户脚本对系统文件、网络或其他敏感资源造成损害。

应用场景:在Xcode中,User Script Sandboxing可以确保用户自定义的脚本或工具在开发过程中不会意外地修改系统文件或访问敏感数据。在浏览器扩展或用户脚本中,Sandboxing可以确保这些脚本不会访问或修改它们不应该访问的网页内容或用户数据。

优化项目结构

删除 SceneDelegate.h 和 SceneDelegate.m,删除 Main.storyboard,删除项目配置中与 Main.storyboard 相关的东西,删除 Info.plist 的内容。

纯代码方式重写主界面

ViewController.h:

objc 复制代码
#import <UIKit/UIKit.h>
#import "PlaceCell.h"
#import "DetailViewController.h"

@interface ViewController : UIViewController
    <UITableViewDelegate, UITableViewDataSource, PlaceCellDelegate, DetailViewControllerDelegate>

@property (nonatomic, strong) UILabel *labelTitle;
@property (nonatomic, strong) UIView *dividerView1;
@property (nonatomic, strong) UILabel *labelFavor;
@property (nonatomic, strong) UISwitch *favoriteSwitch;
@property (nonatomic, strong) UIView *dividerView2;
@property (nonatomic, strong) UITableView *placeTable;

@property (nonatomic, strong) NSMutableArray *data; // 完整数据源
@property (nonatomic, strong) NSMutableArray *places; // 过滤数据源

- (void)initPlaces;

@end

界面实现:

objc 复制代码
- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
    [self.view setBackgroundColor:UIColor.whiteColor];

    CGRect labelTitleFrame = CGRectMake(0, 0, 200, 80);
    CGRect dividerView1Frame = CGRectMake(0, 0, 300, 1);
    CGRect labelFavorFrame = CGRectMake(0, 0, 150, 50);
    CGRect favoriteSwitchFrame = CGRectMake(0, 0, 51, 31);
    CGRect dividerView2Frame = CGRectMake(0, 0, 300, 1);
    CGRect placeTableFrame = CGRectMake(0, 0, 400, 500);

    // 创建并设置 labelTitle
    self.labelTitle = [[UILabel alloc] initWithFrame:labelTitleFrame];
    // 设置应用标题的字体
    UIFont *labelTitleFont = [UIFont fontWithName:@"Helvetica-Bold" size:38];
    [self.labelTitle setFont:labelTitleFont];
    [self.labelTitle setText:@"Landmarks"];
    self.labelTitle.translatesAutoresizingMaskIntoConstraints = NO;

    // 创建并设置 dividerView1
    self.dividerView1 = [[UIView alloc] initWithFrame:dividerView1Frame];
    [self.dividerView1 setBackgroundColor:[[UIColor lightGrayColor] colorWithAlphaComponent:0.5]];
    self.dividerView1.translatesAutoresizingMaskIntoConstraints = NO;

    // 创建并设置 labelFavor
    self.labelFavor = [[UILabel alloc] initWithFrame:labelFavorFrame];
    // 设置标签的字体
    UIFont *labelFavorFont = [UIFont systemFontOfSize:18];
    [self.labelFavor setFont:labelFavorFont];
    [self.labelFavor setText:@"Favorites only"];
    self.labelFavor.translatesAutoresizingMaskIntoConstraints = NO;

    // 创建并设置 favoriteSwitch
    self.favoriteSwitch = [[UISwitch alloc] initWithFrame:favoriteSwitchFrame];
    self.favoriteSwitch.translatesAutoresizingMaskIntoConstraints = NO;
    // 添加目标-动作对
    [self.favoriteSwitch addTarget:self action:@selector(favoriteSwitchValueChanged:) forControlEvents:UIControlEventValueChanged];

    // 创建并设置 dividerView2
    self.dividerView2 = [[UIView alloc] initWithFrame:dividerView2Frame];
    [self.dividerView2 setBackgroundColor:[[UIColor lightGrayColor] colorWithAlphaComponent:0.5]];
    self.dividerView2.translatesAutoresizingMaskIntoConstraints = NO;

    // 创建并设置 placeTable
    self.placeTable = [[UITableView alloc] initWithFrame:placeTableFrame];
    [self.placeTable setSeparatorStyle:UITableViewCellSeparatorStyleSingleLine];
    [self.placeTable setSeparatorColor:UIColor.lightGrayColor];
    self.placeTable.translatesAutoresizingMaskIntoConstraints = NO;
    // 将当前对象设置为 UITableView 对象的 dataSource
    [self.placeTable setDataSource:self];
    // 设置 UITableViewDelegate
    self.placeTable.delegate = self;
    // 需要创建新的单元格时,告诉 UITableView 对象要实例化哪个类
    [self.placeTable registerClass:[PlaceCell class] forCellReuseIdentifier:@"PlaceCellIdentfier"];
    self.placeTable.backgroundColor = [UIColor whiteColor];
    
    [self initPlaces];
    self.places = [NSMutableArray arrayWithArray:self.data];

    [self.view addSubview:self.labelTitle];
    [self.view addSubview:self.dividerView1];
    [self.view addSubview:self.labelFavor];
    [self.view addSubview:self.favoriteSwitch];
    [self.view addSubview:self.dividerView2];
    [self.view addSubview:self.placeTable];
    
    /* 添加约束 */
    [NSLayoutConstraint activateConstraints:@[
        [self.labelTitle.topAnchor constraintEqualToAnchor:self.view.topAnchor constant:95],
        [self.labelTitle.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:20],
    ]];
    
    [NSLayoutConstraint activateConstraints:@[
        [self.dividerView1.topAnchor constraintEqualToAnchor:self.labelTitle.bottomAnchor constant:10],
        [self.dividerView1.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:20],
        [self.dividerView1.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:0],
        [self.dividerView1.heightAnchor constraintEqualToConstant:1]
    ]];
    
    [NSLayoutConstraint activateConstraints:@[
        [self.labelFavor.topAnchor constraintEqualToAnchor:self.dividerView1.bottomAnchor constant:0],
        [self.labelFavor.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:20],
        [self.labelFavor.heightAnchor constraintEqualToConstant:50]
    ]];
    
    [NSLayoutConstraint activateConstraints:@[
        [self.favoriteSwitch.centerYAnchor constraintEqualToAnchor:self.labelFavor.centerYAnchor],
        [self.favoriteSwitch.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-20],
    ]];
    
    [NSLayoutConstraint activateConstraints:@[
        [self.dividerView2.topAnchor constraintEqualToAnchor:self.labelFavor.bottomAnchor constant:0],
        [self.dividerView2.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:20],
        [self.dividerView2.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:0],
        [self.dividerView2.heightAnchor constraintEqualToConstant:1]
    ]];
    
    [NSLayoutConstraint activateConstraints:@[
        [self.placeTable.topAnchor constraintEqualToAnchor:self.dividerView2.bottomAnchor constant:0],
        [self.placeTable.widthAnchor constraintEqualToAnchor:self.view.widthAnchor],
        [self.placeTable.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor constant:0]
    ]];
}

用 Lookin 去查看各组件的位置,效果比较好:

设置详情页的返回按钮的文本

以前是Back,要改成Landmarks。

实际上这个返回按钮是导航条的 backBarButtonItem,新建一个 UIBarButtonItem,再设置即可:

objc 复制代码
self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Landmarks" style:UIBarButtonItemStylePlain target:nil action:nil];

Switch切换TableView展示数据

按 favorite 属性进行筛选,当 Switch 的状态为On时,PlaceTable 只显示收藏的景点,即 favorite=YES 的 Place 对象对应的 PlaceCell。

新增一个 Place 对象数组:data,将其作为完整数据源,而之前的 places 数组作为过滤数据源。修改 initPlaces 方法,从 plist 读的数据不存储在 places 数组里,转而存储在 data 数组里。

在 Switch 的 ValueChange 事件中,如果当前 Switch 的状态为 On,那么遍历 data 数组,将所有 favorite=YES 的 Place 对象插入 places 数组;否则,places = data。还是将 places 作为 PlaceCell 的数据源进行设置,最后别忘了 placeTable 要重新加载数据。

objc 复制代码
- (void)favoriteSwitchValueChanged:(UISwitch *)sender {
    if ([sender isOn])
    {
        [self.places removeAllObjects];
        for (Place *p in self.data)
        {
            if ([p favorite])
            {
                [self.places addObject:p];
            }
        }
    }
    else
    {
        self.places = [NSMutableArray arrayWithArray:self.data];
    }
    [self.placeTable reloadData];
}

更新 PlaceCellDelegate 协议

删除了 PlaceCellDelegate.h,协议声明放到 PlaceCell.h 里。

将可选方法:

复制代码
- (void)updateFavorite:(BOOL)newFavorite atPlaceCell:(PlaceCell *)cell;

修改成:

objc 复制代码
- (void)placeCell:(PlaceCell *)cell updateFavorite:(BOOL)favorite;

其他相关代码也一起修改。

设置 AppIcon

用 AI 生成一个 1024*1024 分辨率的图片,放到 Assets 的 AppIcon 里即可。

相关推荐
2501_915918413 小时前
HTTPS 代理失效,启用双向认证(mTLS)的 iOS 应用网络怎么抓包调试
android·网络·ios·小程序·https·uni-app·iphone
Swift社区3 小时前
Flutter 路由系统,对比 RN / Web / iOS 有什么本质不同?
前端·flutter·ios
zhyongrui4 小时前
SnipTrip 发热优化实战:从 60Hz 到 30Hz 的性能之旅
ios·swiftui·swift
Andy Dennis4 小时前
ios开发 xcode配置
ios·cocoa·xcode
JoyCong19984 小时前
iOS 27 六大功能前瞻:折叠屏、AI Siri与“雪豹式”流畅体验,搭配ToDesk开启跨设备新协作
人工智能·ios·cocoa
linweidong4 小时前
屏幕尺寸的万花筒:如何在 iOS 碎片化生态中以不变应万变?
macos·ios·移动开发·objective-c·cocoa·ios面试·ios面经
Cestb0n5 小时前
iOS 逆向分析:东方财富请求头 em-clt-auth 与 qgqp-b-id 算法还原
python·算法·ios·金融·逆向安全
00后程序员张6 小时前
无需越狱,来对 iOS 设备进行调试、管理与分析
android·ios·小程序·https·uni-app·iphone·webview
00后程序员张6 小时前
在 iOS 上架中如何批量方便快捷管理 Bundle ID
android·ios·小程序·https·uni-app·iphone·webview
山东布谷网络科技7 小时前
海外1v1视频社交APP开发难点与核心功能全解析
开发语言·数据库·mysql·ios·php·音视频·软件需求