仿微博、简书、个人页

2019 年 1 月 3 日 CocoaChina

YSMContainerView


一个易于接入的,思路简洁的仿微博简书等个人页的轮子。


Demo地址


起因:以前去新浪面试被问到了微博个人页的实现,应该是考查手势冲突的问题,当时回答的怎么样已经忘了。回来之后自己实现了一个,但是扩展性始终不太好,最近仿照UITableView的方式重新实现了一个版本。


介绍


YSMContainerView: 继承自UIView,是整个视图的容器。


YSMContainerViewDataSource:YSMContainerView的代理dataSource,负责提供内容。


@required

// 子视图控制器的个数

- (NSInteger)numberOfViewControllersInContainerView:(YSMContainerView *)containerView;

// 根据下标传入响应的子视图

- (UIViewController*)containerView:(YSMContainerView *)containerView viewControllerAtIndex:(NSInteger)index;



@optional

// header view

- (UIView *)headerViewForContainerView:(YSMContainerView *)containerView;


YSMContainerViewDelegate:YSMContainerView 的事件代理。


@optional

// Horizontal Scroll

// 将要水平滚动

- (void)containerView:(YSMContainerView *)containerView willScrollToChildControllerIndex:(NSInteger)index;

// 水平滚动完成

- (void)containerView:(YSMContainerView *)containerView didScrollToChildControllerIndex:(NSInteger)index;



// Vertical Scroll

// 垂直滚动

- (void)containerView:(YSMContainerView *)containerView didScrollContentOffset:(CGPoint)contentOffset;


YSMContainrerChildControllerDelegate:子视图控制器需要实现的方法,YSMContainerView 通过这个代理从子视图控制器中获取 ScrollView(或者其子类)。只有一个方法


// 返回子视图控制器的可滚动的视图

- (UIScrollView *)childScrollView;


使用


1.创建child controller并实现YSMContainrerChildControllerDelegate代理方法。


- (UIScrollView *)childScrollView{

    return self.tableView;

}


2.YSMContainerView初始化。

self.containerView = [[YSMContainerView alloc] initWithFrame:self.view.bounds];

    self.containerView.dataSource = self;

    [self.view addSubview:self.containerView];


3.实现YSMContainerViewDataSource代理的方法。


- (NSInteger)numberOfViewControllersInContainerView:(YSMContainerView *)containerView {

return self.viewControllers.count;

}

- (UIViewController*)containerView:(YSMContainerView *)containerView viewControllerAtIndex:(NSInteger)index {

    UIViewController* childController = self.viewControllers[index];

    return childController;

}


注意:第一步中,因为使用的是懒加载,YSMContainrerChildControllerDelegate代理方法不能返回空,如果在viewDidLoad方法中或之后初始化,会在添加sub view 时获取不到ScollView,而出现空页面。


实现思路


滚动分为横向滚动和纵向滚动,横向切换子视图控制器,纵向滚动子视图控制器。采用的是UICollectionView嵌套 UIScrollView(或者其子类)的方式。


  • 设置UICollectionViewCell的大小为当前页面的大小,UICollectionView只可以横向滚动。

flowLayout.scrollDirection = UICollectionViewScrollDirectionHorizontal;

flowLayout.itemSize = self.bounds.size;

flowLayout.minimumLineSpacing = 0;

flowLayout.minimumInteritemSpacing = 0;


  • 纵向直接滚动子视图控制器的UIScorllView(或者其子类)。


主要实现难点在于处理横向和纵向滚动,于是整理主要思路:


1.header view 是添加到 UICollectionView 上,而不是child controller的header。

2.根据header的高度,依次设置子视图控制器ScrollView的 contentInset 属性,使其内容向下偏移header的高度,呈现header是在child controller 上的效果。


UIEdgeInsets contentInset = UIEdgeInsetsMake(_headerViewHeight, 000);

childScrollView.contentInset = contentInset;

childScrollView.scrollIndicatorInsets = contentInset;


3.设置UICollectionView的delegate方法,在横向滚动时,获取偏移量,设置 headerView 同步横向偏移,实现headerView 始终保持在子视图的上方。


- (void)scrollViewDidScroll:(UIScrollView *)scrollView{

    // 水平移动时 控制header水平同步位移

    CGRect headerFrame = self.containerHeaderView.frame;

    headerFrame.origin.x = scrollView.contentOffset.x;

    self.containerHeaderView.frame = headerFrame;

}


4.在添加child controller时,添加观察者,监听子视图ScrollView的contentOffset属性。


[childScrollView addObserver:self forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionNew context:nil];


5.纵向滚动时,会出发KVO监听方法,在回调中可以拿到当前子视图控制器的偏移量,然后设置header同步纵向偏移,实现滚动headerView的效果。


- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary*)change context:(void *)context{

    if (![keyPath isEqualToString:@"contentOffset"]) {

        return [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];

    }

    CGPoint contentOffset = [[change valueForKey:NSKeyValueChangeNewKeyCGPointValue];

// 根据contentOffset的位置同步偏移 header view,设置悬停位置。

}


TODO

  1. 进一步封装,子视图添加 tab,点击切换子视图,tab随子视图滚动切换。

  2. 指定移除子视图控制器。

  3. 完善YSMContainerViewDelegate方法。


参考

HJTabViewController

本公众号转载内容已尽可能注明出处,如未能核实来源或转发内容图片有权利瑕疵的,请及时联系本公众号进行修改或删除【联系方式QQ : 3442093904  邮箱:support@cocoachina.com】。文章内容为作者独立观点,不代表本公众号立场。版权归原作者所有,如申请授权请联系作者,因文章侵权本公众号不承担任何法律及连带责任。

---END---


登录查看更多
0

相关内容

ACL2020接受论文列表公布,571篇长文208篇短文
专知会员服务
66+阅读 · 2020年5月19日
专知会员服务
109+阅读 · 2020年3月12日
抢鲜看!13篇CVPR2020论文链接/开源代码/解读
专知会员服务
49+阅读 · 2020年2月26日
谷歌机器学习速成课程中文版pdf
专知会员服务
145+阅读 · 2019年12月4日
【干货】大数据入门指南:Hadoop、Hive、Spark、 Storm等
专知会员服务
95+阅读 · 2019年12月4日
产品经理们,好好琢磨产品定位吧
产品100干货速递
7+阅读 · 2019年6月4日
CVPR19 | SiamMask作者有话说——我对Siamese网络的一点思考
人工智能前沿讲习班
4+阅读 · 2019年3月10日
iOS自定义带动画效果的模态框
CocoaChina
7+阅读 · 2019年3月3日
能不能进苹果做 AI,就看这 20 道面试题了
AI研习社
7+阅读 · 2018年5月3日
浅谈浏览器 http 的缓存机制
前端大全
6+阅读 · 2018年1月21日
Meta-Learning to Cluster
Arxiv
17+阅读 · 2019年10月30日
Monocular Plan View Networks for Autonomous Driving
Arxiv
6+阅读 · 2019年5月16日
VIP会员
相关资讯
产品经理们,好好琢磨产品定位吧
产品100干货速递
7+阅读 · 2019年6月4日
CVPR19 | SiamMask作者有话说——我对Siamese网络的一点思考
人工智能前沿讲习班
4+阅读 · 2019年3月10日
iOS自定义带动画效果的模态框
CocoaChina
7+阅读 · 2019年3月3日
能不能进苹果做 AI,就看这 20 道面试题了
AI研习社
7+阅读 · 2018年5月3日
浅谈浏览器 http 的缓存机制
前端大全
6+阅读 · 2018年1月21日
Top
微信扫码咨询专知VIP会员