3G Share仿写总结
文章目录
登录页

这里其实就是一个登录注册视图转换,进行密码验证就好
其中的一个重点在于键盘弹出整个页面上移
这里我用的是系统键盘弹出的通知,比如UIKeyboardWillShowNotification,UIKeyboardDidShowNotification等等,这些通知携带的useInfo会有键盘动画前后的frame,动画时长等,所以我们可以直接根据,通知携带的useInfo完成上移:
objc
- (void)keyboardWillShow:(NSNotification *)notification {
CGRect keyboardFrame = [notification.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
CGFloat keyboardHeight = keyboardFrame.size.height;
CGFloat duration = [notification.userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue];
[UIView animateWithDuration:duration animations:^{
self.view.transform = CGAffineTransformMakeTranslation(0, -keyboardHeight / 2);
}];
}
⚠️由于登录和注册页都要使用这个通知,所以这里需要注意的是这里的通知需要注册到viewWillAppear以及在viewWillDisappear:移除监听
因为注册在viewDidLoad会有问题,会导致如果从注册页返回时键盘收起 的通知还会同时触发LoginVC 的 keyboardWillHide 导致 LoginVC 的 view 执行了一次 CGAffineTransformIdentity 复位,但是此时的但 LoginVC 的 view 此时不一定是偏移状态,就会多次移位导致奇怪的下降或上移,所以我们要在页面出现时再注册监听,同时页面消失的时候复位并移除监听
而且由于当前LoginVC 上移,键盘透明会显示出下层window视图的背景颜色,所以还需要给window层设置一下背景颜色
首页

这一页主要就是一个tableView和轮播图,以及一个点赞传值的功能
-
轮播图的内容我在NStimer中讲过这里就不再介绍
-
点赞传值我其实就是把整个share的所有有关文章显示的内容做了一个单例,然后通过通知传值在某一处被点赞后修改model值并通知其他地方刷新点赞状态
⚠️注意这里的点赞通知不能像注册页注册在viewWillAppear,这样会导致离开该页面就移除监 听,这样也就听不到其他界面的点赞通知,只能在每次viewWillAppear再进行一次页面刷新(viewDidLoad只会调用 一次,所以model被改变要刷新),所以最好把通知注册到 viewDidLoad,并在dealloc中移除监听
- 最后一个就是假日页图片展示的部分,这里我用约束链打算让图片自己的高度撑起cell的高度,但是由于在自定义cell
init的时候无法将图片model传入,只能在后续update的时候传入图片数据,所以在init写UIImageView约束的时候不知道图片高度,cell和图片互相依赖约束,系统无法进行计算
所以必须在update传入图片的时候根据图片真实比例更新高度约束
你可能会像在有一些文本撑起cell高度的时候就没有这个问题是因为高度是由"内容 + font"自动 决定的 (Intrinsic Content Size)
objc
// HolidayPhotoCell.m
- (void)updateWithModel:(NSArray *)model index:(NSInteger)index {
UIImage *image = [UIImage imageNamed:model[index]];
self.imaV.image = image;
if (image) {
CGFloat ratio = image.size.height / image.size.width;
CGFloat screenWidth = [UIScreen mainScreen].bounds.size.width;
CGFloat imageHeight = screenWidth * ratio;
[self.imaV mas_updateConstraints:^(MASConstraintMaker *make) {
make.height.mas_equalTo(imageHeight);
}];
}
}
搜索页

这一页主要就是原本的标签页,大白页和上传页
- 标签页我采用的是
UICollectionView,再写一个self.collection.allowsMultipleSelection = YES;允许多选就行 - 大白页根据
UITextFieldDelegate代理方法进行视图转换 - 上传页的图片选择器,我在上一篇PHPickerViewController笔记中有讲到,这里就不再赘述
- 上传页的"原创作品"展开选项原理类似于折叠cell,我这里是一个text为"原创作品",image为"chevron.down"的button,以及一个展示选项的tableView,这个tableView在最初没有点击展开的时候它的约束高度为0,
make.height.mas_equalTo(0);并将这个约束进行保存,在button被点击之后更新tableView的高度,并且做一个"chevron.down"箭头图标旋转的动画就会有展开的感觉,收起也是同理
注意这里在每次展开后要设置 [self.view bringSubviewToFront:self.dropList];将选项列表 展示在最上层防止被其他控件挡住
文章页

这里我写的是支持横向滚动的ScrollView里装三个TableView
-
这里需要注意的就是要开启
UIScrollView的方向锁定 ,self.scr.directionalLockEnabled = YES;,也就是用户开始滑动的时候,系统会根据一开始的滑动方向,尽量锁定成横向滑动 或者纵向滑动,不然的话你的ScrollView可能就会有能斜着滑动的问题 -
再就是
UIScrollView的滑动和UISegmentedControl尽量同步,也就是说不要在滑动视图结束滚动的协议方法里修改UISegmentedControl的索引位置,这样会看起来很突然的移动,在实时滚动的协议方法里进行页吗判断objc- (void)scrollViewDidScroll:(UIScrollView *)scrollView { // 因为tableView也继承于UIScrollView // 所以 tableView 滚动也会触发 scrollViewDidScroll:,就会导致竖直滑动tableView的时候segmentControl也会移动 // 只处理横向翻页的 scr,忽略 tableView 的滚动 if (scrollView != self.scr) return; CGFloat pageWidth = scrollView.bounds.size.width; CGFloat offset = scrollView.contentOffset.x; CGFloat realPage = offset / pageWidth; NSInteger index = (NSInteger)(realPage + 0.5); index = MAX(0, MIN(index, 2)); self.titleSeg.selectedSegmentIndex = index; }
活动页

这里就是一个简单的UITableView
个人信息页

这里的难点主要集中在私信发送
我这里是用UITableView,做了两个自定义cell,分别用在左边对方发送气泡和右边我的发送气泡,然后每次点击发送按钮后将textField.text保存到model里,之后在tableView中插入新的一行[self.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationBottom];并且滚动tableView让新消息始终在键盘/屏幕上方[self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];注意这里UITableViewScrollPositionBottom的底部是相对于tableView的,所以最好该页面用约束链将tableView和发送部分连在一起,这样在键盘弹起底部发送部分同步弹起的时候可以将tableView的底部也抬起
这个model里有枚举值用来代表是我还是对方发送的消息,根据这个判断cell复用的时候用的是哪个气泡
这个自定义消息气泡的cell要注意用约束链根据文字内容高度撑开cell高度,这样在用户输入多行文字的时候能够自然的撑起气泡的高度
objc
typedef NS_ENUM(NSInteger, MessageType) {
MessageTypeSelf,
MessageTypeOther
};
@interface ChatModel : NSObject
@property (nonatomic, copy) NSString *content;
@property (nonatomic, copy) NSString *avatar;
@property (nonatomic, assign) MessageType type;
+ (instancetype)modelWithContent:(NSString *)content type:(MessageType) type avatar:(NSString *) avatar;
@end

这里在第二次进入视图还能够保存之前的数据,是我这里把所有model做成一份单例,这样在第二次打开视图的时候就不会初始化覆盖掉
以及我做了一个block传值是的私信列表展示聊天记录的最后一句话