Zhihao's Studio.

仿微信朋友圈/抖音个人主页的设计与实现

Word count: 1,987 / Reading time: 7 min
2019/02/19 Share

背景

因业务发展需要,在新版本的Match问答中,我们决定加入更多的社交元素,方便大家互相勾搭和交流,更多地展现自己的学习日常和个性,在原有版本的基础上计入了动态个人主页两个模块,其中个人主页又分为第一人称视图第三人称视图。本文是我在春节假期期间实现这两个模块的一点小心得

期间参考了大量开源项目的已有代码,进行了借鉴和向Swift 4.2的改写,在此表示感谢,开源项目不完整列表见文末附录。

用户自己的个人主页视图

布局

个人主页视图借鉴了最右这款非常受欢迎的应用,只不过上方的布局稍有不同。其实不止是最右,抖音、微博、知乎等App都有着非常类似的个人主页。

Match与最右的个人主页对比

整个个人主页可分为两部分,第一部分是上方的头像、昵称、性别、个性签名、背景图片的区域;第二部分是下方的配置项,定制化的TableView。

头像外面加了一圈白色的圆,可以更突出头像部分,实现也比较简单,显式指定头像所属imageView的layer的borderWidth和borderColor即可,当然前提是已经将头像裁剪为圆形

Tableview的分割线起始位置的定制:

1
2
3
4
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
tableView.tableFooterView = UIView(frame: CGRect(x: 0, y: 0, width: 0, height: 0))
tableView.separatorInset = UIEdgeInsets(top: 0, left: 50, bottom: 0, right: 0)
}

比起其他应用,我还有一个功能没实现,那就是下拉的时候背景图片的放大。研究过OC代码后,发现这个功能也不难,主要实现方式是didscroll代理方法中监听滑动的偏移量,作为控制image的zoom倍率依据。

头图下拉放大效果

更换背景和头像事件

更换头像和背景思路是类似的,都是给一个图片增加手势事件的识别,通常有两种实现方式。第一种是比较土味的方法,给图片覆盖上一层透明的button,将button设为与图片形状一样;第二种方式是给imageView加上UITapGestureRecognizer,比较简单就不再赘述。

添加或更改图片涉及到图片拉伸的问题,因此需要进行裁剪,头像的比例是1:1,而背景图片比较复杂,为了适应各种手机型号的屏幕,宽度拉到与屏幕等宽,高度和宽度维持一个固定的宽高比,当然这对用户应该是透明的,将裁剪方式的选择权还给用户。

图片裁剪页

他人个人主页的实现

布局

社交的重要一部分是去其他人的个人主页看看,其他人的个人主页和用户自己看自己的个人主页肯定是有区别的。用户自己的主页主要是一个去各种设置的中转站,用户看别人的主页主要是看他人的头像、签名、背景、收入、问答、动态等内容

他人个人主页视图

上半部分和个人主页是一样的设计,下半部分有不同,是一个在其他应用中很受欢迎的左右滑动的Tab,暂且将其命名为swipe view。

实现的关键点与细节

为了让用户可以右滑退出这个页面,我将下方的swipe view的左边距设为了10px,这样方便用户用手势进行退出,保留着navigation ViewController的退出方式。

这个页面的难点是嵌套scrollview的冲突处理,整个页面是被一个scrollview包裹起来的,而swipe view中也是scrollview,这里设定了上方有view的时候,使得滑动相应外层滑动事件,而当swipe view滑动至顶部的时候,将swipe view头固定于信号栏下方,此时的滑动事件相应者为swipe view中的scrollview。

去除了业务逻辑的关键代码片段 (made with Carbonize)

固定住外层scrollview的主要实现方式是设置scrollview.contentOffset.y变量,当swipe view在scrollview中的坐标位置小于某个值的时候,设定scrollview.contentOffset.y为一个定值,这样就固定住了swipe view的表头部分。注意,开始的时候我设定的是isUserInteractionEnabled属性,这样swipe内的所有内容都不能交互了,比如正常的图片也不能点开看大图了。后面改成了isScrollEnabled,这样就不影响除了滑动外的其他操作了。

不足

其实现在实现这个功能还有点美中不足,那就是固定住scrollview是一个滑动操作,而要想接着对swipe view中的scrollview进行滑动,必须再滑动一次,也就是中间必须中断一次。目前还不知道如何将一次滑动操作发给两个响应者进行处理。

朋友圈的设计与实现

微信朋友圈的点赞、留言、回复功能是很多应用都需要的功能,在实现这个功能的时候,我参考了不少优秀的blog和开源代码,并最终选中了【附录4】的OC实现进行了向Swift 4.2的改写,后面根据自己的需求进行了一些定制,主要是点击点赞和评论用户名跳转到他的个人主页。

朋友圈的两种实现方式

【附录6】里介绍了朋友圈有两种主要实现方式,第一种是将每条动态作为TableView的一个cell,然后cell内部的点赞、评论又作为一个TableView,其中点赞作为Header view,每条评论作为二级cell。布局依赖Masonry,是自动布局autolayout技术,并且依赖第三方缓存cell高度进行优化,这种实现方式作者认为代价比较高。主要是页面结构复杂,依赖第三方库Masonry,集成难度较大。

微信朋友圈的两种实现思路

方式二是一个tableView,cell用来展示评论数据,headerView用来展示头像、发布文字和时间等等,主要优化策略也是缓存cell高度,保证后续滑动tableview不会重复计算,提升流畅度,我改写的库也答题是这种思路。

点赞超链接的实现

点赞超链接主要是借助NSAttributedString/NSMutableAttributedString,让用户名高亮为蓝色,并附带上User_id的信息,统一跳转到上文实现的第三人称视图中。

一个优化过的点

朋友圈里有个点我觉得对于用户体验的提升还蛮有优化意义的,那就是防止弹出的键盘遮挡住原动态和评论,下面给出参考的实现方式,主要思路是得到当前的cell,使其滑动。

使得tableview上滑的代码(made with Carbonize)

可优化的点

可优化的点还有很多,作者也列出了一些供大家参考。

  1. cell复用机制+sectionView复用机制
  2. 将cell的高度和cell里控件的frame存在model里
  3. 减少cell内部控件的层级,层级不易太深
  4. 缩略图和大图URL(拿起大刀让后台兄弟去完成,因为后台不提供缩略图功能,朋友圈很容易内存警告)
  5. 图片圆角cornerRadius,缓存圆角等等
  6. 高度缓存(cell评论区高度+section区头高度)
  7. 异步加载渲染(图片+文本+view)(利用SDWebImage异步下载图片,文本和view没完成异步处理)

参考&致谢

  1. PhotoCropEditor
  2. GKPageScrollView
  3. SwipeMenuViewController
  4. MomentKit
  5. iOS 实现微信朋友圈评论回复功能
  6. 朋友圈评论回复的两种实现方式
CATALOG
  1. 1. 背景
  2. 2. 用户自己的个人主页视图
    1. 2.1. 布局
    2. 2.2. 更换背景和头像事件
  3. 3. 他人个人主页的实现
    1. 3.1. 布局
    2. 3.2. 实现的关键点与细节
    3. 3.3. 不足
  4. 4. 朋友圈的设计与实现
    1. 4.1. 朋友圈的两种实现方式
    2. 4.2. 点赞超链接的实现
    3. 4.3. 一个优化过的点
    4. 4.4. 可优化的点
  5. 5. 参考&致谢