【iOS】暑假第二周——网易云APP 仿写

目录

前言

有了之前仿写ZARA的基础,本周我们仿写了网易云APP,在这里对多界面传值进行了首次应用------夜间模式和换头像功能。以下是我在仿写网易云时觉得比较重要的地方和遇到的问题。

首页

主要包含导航栏,搜索框,无限自动轮播图,以及三个UILabel和与之对应的TableView。其中比较重要的是,当用户滑动页面时,页面上的内容跟着画布一起动,而顶部的导航栏则不动,且用户放手后,页面回到原位置。

效果图如下:

其中无限轮播图及自动播放跟zara的仿写的实现方法相同。而下面的红标功能和推荐歌单,最近常听等就是自定义cell和滚动视图的结合。

我这里以推荐歌单部分的滚动视图为例,给出代码:

objectivec 复制代码
//homeTableViewCell.m
    if ([self.reuseIdentifier isEqualToString:@"tuijiangedan"]) {
        _tuijiangedanLabel = [[UILabel alloc] initWithFrame:CGRectMake(5, 0, WIDTH, 20)];
        _tuijiangedanLabel.text = @"  推荐歌单 >";
        _tuijiangedanLabel.textColor = [UIColor blackColor];
        _tuijiangedanLabel.font = [UIFont systemFontOfSize:17];
        _tuijiangedanLabel.backgroundColor = [UIColor whiteColor];
        if (swDelegate.isNighted) {
            _tuijiangedanLabel.backgroundColor = [UIColor grayColor];
            _tuijiangedanLabel.textColor = [UIColor blackColor];
        } else {
            _tuijiangedanLabel.backgroundColor = [UIColor whiteColor];
            _tuijiangedanLabel.textColor = [UIColor blackColor];
        }
        [self.contentView addSubview:_tuijiangedanLabel];
        
        _tuijiangedanScrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 50, WIDTH, 110)];
        _tuijiangedanScrollView.contentSize = CGSizeMake(WIDTH * 2, 130);
        _tuijiangedanScrollView.bounces = YES;
        _tuijiangedanScrollView.alwaysBounceHorizontal = YES;
        _tuijiangedanScrollView.alwaysBounceVertical = NO;
        _tuijiangedanScrollView.showsHorizontalScrollIndicator = YES;
        _tuijiangedanScrollView.scrollEnabled = YES;
        _tuijiangedanScrollView.pagingEnabled = YES;
        
        _tuijiangedanArray = @[@"tuijiangedan1.jpg", @"tuijiangedan2.jpg", @"tuijiangedan3.jpg", @"tuijiangedan4.jpg", @"tuijiangedan5.jpg", @"tuijiangedan6.jpg"];
        _tuijiangedantitleArray = @[@"【华语经典】那些年听不厌的经典😋", @"✨温柔女声·开口惊艳的女声翻唱", @"心动旋律|挖掘星辰大海中的宝藏💎", @"💌短发 故事 与她", @"连空想都红了眼是有多遗憾😔", @"华语宝藏R&B|来自过去的浪漫氛围🌄"];
//        if (swDelegate.isNighted) {
//            _tuijiangedanScrollView.backgroundColor = [UIColor blackColor];
//        } else {
//            _tuijiangedanScrollView.backgroundColor = [UIColor whiteColor];
//        }
        for (int i = 0; i < 6; i++) {
            NSString* str = [[NSString alloc] initWithString:_tuijiangedanArray[i]];
            UIImage* image = [[UIImage alloc] init];
            image = [UIImage imageNamed:str];
            UIImageView* iView = [[UIImageView alloc] initWithImage:image];
            iView.frame = CGRectMake(10 + 130 * i, 0, 110, 110);
            iView.layer.cornerRadius = 7;
            iView.layer.masksToBounds = YES;
            [_tuijiangedanScrollView addSubview:iView];
            
            self.tuijiangedanLabel2 = [[UILabel alloc] initWithFrame: CGRectMake(10 + 130 * i, 110, 120, 50)];
            self.tuijiangedanLabel2.font = [UIFont systemFontOfSize: 14];
            self.tuijiangedanLabel2.text = _tuijiangedantitleArray[i];
            self.tuijiangedanLabel2.textColor = [UIColor blackColor];
            self.tuijiangedanLabel2.numberOfLines = 2;
//            if (swDelegate.isNighted) {
//                _tuijiangedanLabel2.backgroundColor = [UIColor blackColor];
//                _tuijiangedanLabel2.textColor = [UIColor whiteColor];
//            } else {
//                _tuijiangedanLabel2.backgroundColor = [UIColor whiteColor];
//                _tuijiangedanLabel2.textColor = [UIColor blackColor];
//            }
            [self.tuijiangedanScrollView addSubview: self.tuijiangedanLabel2];
        }
        [self.contentView addSubview:_tuijiangedanScrollView];
    } 

在这里学到比较多的是关于导航栏的设置和滑动屏幕时,上面除了导航栏外的内容跟着画布一起动。

下面是导航栏设置的相关代码:

objectivec 复制代码
    UINavigationBarAppearance* appearance = [[UINavigationBarAppearance alloc] init];
    appearance.backgroundColor = [UIColor whiteColor];
    //取消图像阴影
    appearance.shadowImage = [[UIImage alloc] init];
    appearance.shadowColor = nil;
    
    _leftbtn = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"caidan.png"] style:UIBarButtonItemStylePlain target:self action:nil];
    _leftbtn.tintColor = [UIColor redColor];
    _leftbtn.width = 30;
    self.navigationItem.leftBarButtonItem = _leftbtn;
    //[self.tableView reloadData];
    
    _search = [[UISearchBar alloc] init];
    _search.frame = CGRectMake(30, 0, 250, 30);
    self.textField = [[UITextField alloc] initWithFrame:CGRectMake(30, 0, 250, 30)];
    _search.searchBarStyle = UISearchBarStyleMinimal;
    _search.placeholder = @"凤凰传奇";
    _search.keyboardType = UIKeyboardTypeDefault;
    self.navigationItem.titleView = _search;
    
    _rightbtn = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"tinggeshiqu.png"] style:UIBarButtonItemStylePlain target:self action:nil];
    _rightbtn.tintColor = [UIColor redColor];
    _rightbtn.width = 30;
    self.navigationItem.rightBarButtonItem = _rightbtn;
    
    self.navigationController.navigationBar.standardAppearance = appearance;
    self.navigationController.navigationBar.scrollEdgeAppearance = appearance;
    [self.tableView reloadData];

关于UINavigationBarAppearance

UINavigationBarAppearance 的 shadowImage 和 shadowColor 属性用来控制导航栏的阴影效果。默认情况下,导航栏有阴影效果以提升视觉层次感,但你可以根据需要进行自定义。下面是对阴影效果的详细说明解释。

导航栏阴影效果:

  1. 阴影图像 (shadowImage)
  • 默认阴影图像:UINavigationBar 的默认样式通常包括一个阴影图像,这个图像创建了一个底部边缘的阴影效果,使导航栏从下方看起来有一个轻微的阴影。
  • 自定义阴影图像:你可以设置 shadowImage 属性为一个自定义的 UIImage 对象,以改变或移除阴影效果。如果将 shadowImage 设置为一个自定义的图像,它会替换掉默认的阴影效果。
  1. 阴影颜色 (shadowColor)
  • 默认阴影颜色:导航栏的阴影颜色是系统默认的颜色。
  • 自定义阴影颜色:你可以通过 shadowColor 属性设置一个自定义的阴影颜色,或者将其设置为 nil 以移除阴影颜色,使导航栏没有阴影效果。

如何管理和自定义阴影效果:

  1. 移除阴影
    如果你想移除导航栏的阴影效果,可以将 shadowImage 设置为 nil,或者设置一个透明的图像。示例如下:
objectivec 复制代码
UINavigationBarAppearance *appearance = [[UINavigationBarAppearance alloc] init];
appearance.backgroundColor = [UIColor systemBackgroundColor]; // 设置背景颜色
appearance.shadowImage = nil;  // 移除阴影图像
appearance.shadowColor = nil; // 移除阴影颜色(可选)

if (self.navigationController) {
    self.navigationController.navigationBar.standardAppearance = appearance;
    self.navigationController.navigationBar.scrollEdgeAppearance = appearance;
}
  1. 设置自定义阴影图像
    如果你需要自定义阴影效果,可以创建一个带有阴影的 UIImage,然后设置 shadowImage 属性:
objectivec 复制代码
UIImage *customShadowImage = [UIImage imageNamed:@"customShadowImage"]; // 使用自定义的阴影图像
appearance.shadowImage = customShadowImage;

if (self.navigationController) {
    self.navigationController.navigationBar.standardAppearance = appearance;
    self.navigationController.navigationBar.scrollEdgeAppearance = appearance;
}
  1. 调整阴影颜色
    虽然 shadowColor 属性在 UINavigationBarAppearance 中不直接存在,shadowImage 和 backgroundImage 属性间接控制了阴影的显示。在某些情况下,你可能需要通过自定义图像来设置阴影的颜色效果。
    如果需要更新导航栏的外观,移除阴影并应用新的背景颜色,代码示例如下:
objectivec 复制代码
- (void)updateNavigationBarAppearanceWithColor:(UIColor *)newColor {
    UINavigationBarAppearance *appearance = [[UINavigationBarAppearance alloc] init];
    appearance.backgroundColor = newColor;
    appearance.shadowImage = nil;  // 移除默认的阴影图像
    appearance.shadowColor = nil;  // 适配阴影颜色的移除

    if (self.navigationController) {
        self.navigationController.navigationBar.standardAppearance = appearance;
        self.navigationController.navigationBar.scrollEdgeAppearance = appearance;
    }
}

解释

  • shadowImage 控制阴影图像的显示。如果设置为 nil,阴影将被移除。
  • shadowColor 用于设置阴影颜色,但在现代 iOS 开发中,通常通过图像来控制阴影效果。
  • 默认行为:如果未设置 shadowImage,系统将使用默认的阴影效果。
    通过这些方法,你可以自定义导航栏的视觉效果,确保它符合你的应用设计需求。

"我的"

这个界面主要就是滚动视图和分栏控件及滚动视图的结合(这个跟zara仿写里的是一样的),还有就是云盘空间的界面的推出。

下面先给出效果图:

滚动视图跟home界面同理,与分栏控件的结合与zara里面同理。下面给出云盘界面跳转的代码(其实就是为按钮添加事件函数,然后在事件函数里实现页面的推出):

objectivec 复制代码
//云盘空间按钮的设置
    UIImage* icon = [[UIImage alloc] init];
    icon = [UIImage imageNamed:@"cloudbtn.png"];
    CGSize newSize = CGSizeMake(35,35);
    UIGraphicsBeginImageContextWithOptions(newSize, NO, 0.0);
    [icon drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
    UIImage* resizedImage = [[UIImage alloc] init];
    resizedImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    UIBarButtonItem *leftButton = [[UIBarButtonItem alloc] initWithImage:resizedImage style:UIBarButtonItemStylePlain target:self action:@selector(yunpankongjian)];
    leftButton.tintColor = UIColor.redColor;

//按下按钮的函数实现
- (void) yunpankongjian {
    cloudRoomViewController* yun = [[cloudRoomViewController alloc] init];
    yun.hidesBottomBarWhenPushed = YES;
    UIBarButtonItem* bar = [[UIBarButtonItem alloc] initWithTitle:@"" style:UIBarButtonItemStylePlain target:nil action:nil];
    self.navigationItem.backBarButtonItem = bar;
    [self.navigationController pushViewController:yun animated:YES];
}

账号

账号页面没什么复杂的东西,就是一个tableView,最关键的是夜间模式的按钮,要将按钮状态传到其他页面,为夜间模式作铺垫。

效果图如下:

夜间模式------多界面传值

这里先给出效果图:

我们这里主要使用的的属性传值,在appDelegate.m里设置一个属性,可以被整个程序访问,通过按钮的开关状态来改变view,label和text的相关颜色。然后在每个自定义cell里设置开关打开后,控件的颜色状态即可(类似于下面的代码)。关于属性传值,可以去看我的上一篇博客。

objectivec 复制代码
if (swDelegate.isNighted) {
            [_starListbutton setTintColor: UIColor.grayColor];
            [_myListbutton setTintColor: UIColor.grayColor];
            [_starListbutton setTitleColor:UIColor.lightGrayColor forState:UIControlStateNormal];
            [_myListbutton setTitleColor:UIColor.lightGrayColor forState:UIControlStateNormal];
            [_starListbutton setTitleColor:UIColor.whiteColor forState:UIControlStateSelected];
            [_myListbutton setTitleColor:UIColor.whiteColor forState:UIControlStateSelected];
        } else {
            [_starListbutton setTintColor: UIColor.whiteColor];
            [_myListbutton setTintColor: UIColor.whiteColor];
            [_starListbutton setTitleColor:UIColor.grayColor forState:UIControlStateNormal];
            [_myListbutton setTitleColor:UIColor.grayColor forState:UIControlStateNormal];
            [_starListbutton setTitleColor:UIColor.blackColor forState:UIControlStateSelected];
            [_myListbutton setTitleColor:UIColor.blackColor forState:UIControlStateSelected];
        }

遇到的问题

对于各种view的层级关系还不是特别清晰明了,有时候会出现,view在视图上被遮盖,显示不出来的情况。自定义cell时,有时对cell的尺寸拿捏不好,需要来回改动,比较浪费时间。

在用导航栏创建图像时,如果需要透明,要注意移除图像阴影。

mycell里点击单元格松手后,单元格依旧是灰色的,没有恢复到点击前的状态,需要使用deselectRowAtIndexPath: 方法。

对于五种多界面传值理解的还不是很透彻。

所用到的其他知识整理

NSNotification

NSNotification是 iOS 和 macOS 中用于传递信息的类,它是 NSNotificationCenter 的重要组成部分。通知(NSNotification)用于在应用程序的不同部分之间传递信息,而不需要这些部分直接相互引用。这种机制非常适合于解耦合的通信方式,尤其是在复杂的应用中。

主要特点:

  1. 封装通知信息:
    NSNotification 类封装了有关通知的所有信息,包括通知的名称、发送通知的对象以及任何附加的数据(userInfo 字典)。
  2. 通知的创建和发送:
    通知通常由某个对象创建并发送,其他对象可以注册为观察者,以便在通知发送时执行特定的操作。

主要属性和方法:

  1. name 属性:
    通知的名称,是一个 NSString 类型的属性。它用于标识通知的类型。
  2. object 属性:
    发送通知的对象。这可以是任何对象,通常是发送通知的对象本身。接收通知的观察者可以选择只对特定对象发送的通知做出响应,或者不关心对象(即 nil)。
  3. userInfo 属性:
    一个字典(NSDictionary),用于传递附加信息。这个字典可以包含任何类型的键值对,用于通知的详细数据。
  4. 初始化方法:
objectivec 复制代码
- (instancetype)initWithName:(NSString *)name object:(nullable id)object userInfo:(nullable NSDictionary *)userInfo;

    * name:通知的名称。
    * object:发送通知的对象(可以是 nil)。
    * userInfo:附加信息字典(可以是 nil)。

reloadData

在 iOS 开发中,reloadData 是一个常用的方法,主要用于刷新视图控件中的数据内容。这个方法通常用于表视图(UITableView)或集合视图(UICollectionView),它会重新加载视图控件中的所有数据项,并刷新界面的显示。

  1. UITableView 中的 reloadData:

用途:在 UITableView 中,reloadData 会重新加载表视图中的所有数据,刷新所有的单元格(UITableViewCell)。这在数据源发生变化后非常有用,例如数据从网络加载完成后,或者数据被修改时。

调用方式:

objectivec 复制代码
[self.tableView reloadData];

注意事项:

在调用 reloadData 时,表视图会重新调用数据源方法来更新所有单元格,因此要确保数据源的数据是最新的。

* reloadData 会使整个表视图重新加载,这可能会导致性能开销,特别是在表视图包含大量数据时。

  1. UICollectionView 中的 reloadData
    用途:在 UICollectionView 中,reloadData 会重新加载集合视图中的所有项(UICollectionViewCell)。适用于集合视图的数据源发生变化时,刷新整个集合视图的显示。
    调用方式:
objectivec 复制代码
[self.collectionView reloadData];

注意事项:

与 UITableView 类似,reloadData 会导致集合视图重新调用数据源方法,并重新布局所有单元格。这可能会影响性能,尤其是当集合视图中包含大量数据项时。

各种键盘模式

UIKeyboardTypeDefault: 默认键盘类型,适用于一般文本输入。

UIKeyboardTypeASCIICapable:ASCII字符键盘,适用于只需要ASCII字符的输入。

UIKeyboardTypeNumbersAndPunctuation:数字和标点符号键盘,适用于需要输入数字和标点符号的场景。

UIKeyboardTypeURL:专门用于输入URL的键盘,通常包括用于输入斜杠的特殊键。

UIKeyboardTypeNumberPad:仅包含数字的键盘,适用于仅需要输入数字的场景,如电话号码或计算器输入。

UIKeyboardTypePhonePad:专为电话号码输入设计的键盘,包含常用的电话号码符号。

UIKeyboardTypeEmailAddress:适用于电子邮件地址输入的键盘,包含电子邮件地址输入所需的特殊字符。

UIKeyboardTypeDecimalPad:数字键盘,包含一个小数点,用于输入需要小数点的数字。

UIKeyboardTypeWebSearch:用于 Web 搜索的键盘,包含搜索相关的字符和布局。

总结

刚开始写网易云可能会比较慢,对于知识的运用和视图控件位置的把控不太好,在这个仿写中不但复习了之前学的知识,而且也学到了reloadData等新知识,也粗略学习了多界面传值的知识,为后面3G share的仿写作铺垫。

相关推荐
Digitally2 小时前
如何用4 种可靠的方法更换 iPhone(2025 年指南)
ios·iphone
9765033355 小时前
iOS 审核 cocos 4.3a【苹果机审的“分层阈值”设计】
flutter·游戏·unity·ios
I烟雨云渊T5 小时前
iOS Alamofire库的使用
ios
程序员老刘·5 小时前
iOS 26 beta1 真机无法执行hot reload
flutter·ios·跨平台开发·客户端开发
EndingCoder5 小时前
React Native 构建与打包发布(iOS + Android)
android·react native·ios
程序员小刘6 小时前
HarmonyOS 5鸿蒙多端编译实战:从Android/iOS到HarmonyOS 5 的跨端迁移指南详
android·ios·华为·harmonyos
I烟雨云渊T6 小时前
iOS swiftUI的实用举例
ios·swiftui·swift
getapi7 小时前
将 App 安装到 iPhone 真机上测试
ios·iphone
2501_9222329417 小时前
Mac电脑 系统监测工具 System Dashboard Pro
macos
90后的晨仔21 小时前
RxSwift 中的 `Single`:单元素响应式编程简单实践
ios