网易新闻顶部效果

来源:互联网 发布:mac office 2016 卸载 编辑:程序博客网 时间:2024/05/21 10:27

没想到有一天我竟然真的进入了我梦寐以求的网易,虽然只是个实习生~

也没想到第一个正式的任务就是做个网易新闻顶部的效果。因为之前有好多面试官都问过我类似的问题,要么就是问网易新闻顶部的这个效果,要么就是问知乎日报顶部的那个效果,没想到现在我还真要做这个了偷笑

说了半天废话,到底是啥效果?(下个iOS版的网易新闻不就知道了。。。)(和安卓版的不一样)

我做的效果如下图:



刚开始感觉好难。几乎没什么思路。后来冷静思考了下,先是想修改下边那个tableView的contentOffset,后来又想改tableView的contentSize,还想过把上面的view和下面的tableView拼接到一起,还想过修改上面的view的contentOffset。。。。。。


但是后来我发现这些想法都是错误的。。。(天,这就是我冷静思考后的结果么。。。)


最后想到,其实只要修改上面的view的frame和下面的tableView的frame就可以了。


那么怎么做呢?

利用KVO监听。

static NSString *const kContentOffset = @"contentOffset";- (void)viewWillAppear:(BOOL)animated {    [super viewWillAppear:animated];    [self.tableView addObserver:self forKeyPath:kContentOffset options:0 context:nil];}- (void)viewWillDisappear:(BOOL)animated {    [super viewWillDisappear:animated];    [self.tableView removeObserver:self forKeyPath:kContentOffset];}


我们监听tableView的contentOffset,划动的时候它的contentOffset会发生变化,这样我们就可以根据它的contentOffset来动态地修改它的frame和顶部topView的frame。

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {    if ([keyPath isEqualToString:kContentOffset]) { // 监听的是contentOffset的变化        [self.tableView removeObserver:self forKeyPath:kContentOffset]; // 这里需要先移除监听,否则会导致死循环                CGFloat newY = self.tableView.contentOffset.y; // 获取划动的contentOffset的y值        CGFloat topY = CGRectGetHeight(self.topView.frame); // topView的高度                if (newY <= 0) { // topView在底部,此时只有tableView动            self.tableView.frame = CGRectMake(0, topY, ScreenWidth, ScreenHeight-topY);        } else if (newY > 0 && newY < topY-64) { // topView在中间,两者都动            self.tableView.frame = CGRectMake(0, topY-newY, ScreenWidth, ScreenHeight-(topY-newY));            self.topView.frame = CGRectMake(0, -newY, ScreenWidth, topY);        } else if (newY >= topY-64) { // topView在顶部,此时只有tableView动            self.tableView.frame = CGRectMake(0, 64, ScreenWidth, ScreenHeight-64);        }                [self.tableView addObserver:self forKeyPath:kContentOffset options:0 context:nil]; // 结束后再添加监听    }}


其实只需要分成三种情况来考虑就可以了。即:topView在顶部、topView在中间、topView在底部。

注意:一开始的时候需要先移除监听,否则会导致死循环,之后再添加监听即可。


然后是关于topView的部分。怎么让topView中的控件逐渐变透明,并且在划动到一定程度后消失,同时产生一个新的名字label呢?

刚开始的时候我的想法是通过layoutSubviews方法来修改。但是通过这个栗子我发现原来并不是frame变了就会调用layoutSubviews,而是frame的size变了才会调用它。在这个栗子中,我们修改的是frame.origin.y,并没有修改frame的size,topView的宽和高始终没有发生过变化,只不过它的y值在动态的改变而已。所以通过layoutSubviews 的方法不可行。

那怎么做呢?


还是监听。只不过刚才我们监听的是tableView的contentOffset,而现在我们需要监听的是topView的frame。

static NSString *const kFrame = @"frame";[self addObserver:self forKeyPath:kFrame options:0 context:nil];
在topView中自己监听自己的frame的变化,然后动态修改自己的控件的alpha属性。

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {    if ([keyPath isEqualToString:kFrame]) {        CGFloat originY = -self.frame.origin.y;                CGFloat alpha = originY / ((CGRectGetHeight(self.frame)-64)/2);        self.avatar.alpha = 1 - alpha;        if (alpha >= 1.0) { // 原本的控件逐渐变透明            self.nameLabel.center = CGPointMake(ScreenWidth/2, CGRectGetHeight(self.frame)-CGRectGetHeight(self.nameLabel.frame)/2-10);            self.nameLabel.alpha = alpha - 1;        } else { // 原本的控件已经完全透明了,产生一个新的(其实用的还是旧的控件,只不过把frame改了)            self.nameLabel.center = CGPointMake(ScreenWidth/2, CGRectGetMaxY(self.avatar.frame)+20);            self.nameLabel.alpha = 1 - alpha;        }    }}


核心代码就是这些,demo的完整源码可以去我的GitHub下载:https://github.com/963239327/NETopView












1 0
原创粉丝点击