美文网首页iOS开发进阶之路iOS开发动画相关
仿淘宝上拉进入详情页交互的实现

仿淘宝上拉进入详情页交互的实现

作者: Wang66 | 来源:发表于2016-08-28 16:01 被阅读12081次

    前言

    项目某个新需求的交互要求仿照淘宝上拉从下网上弹出宝贝详情。今天打开淘宝APP仔细看了看,然后自己写了写,现在感觉效果差不多了,记录一下。


    分析

    可以看到,该页面是分为两部分的,一部分是一开始就能看到的商品信息,然后我们上拉屏幕,屏幕不断往上滚动,滚动到第一部分结束时可以看到底部有“继续拖动,查看图文详情”一行文本出现。继续上拉到一个临界点便触发了翻页,此时第二部分以动画的形式从底部涌出占满整个屏幕。而且效果是该页面整体上移了,即第一部分和第二部分都是上移的。
    此时,第二部分占满着整个屏幕,若我们下拉屏幕,则在屏幕顶部淡出“下拉,返回宝贝详情”的文本提示,并且达到一个临界值后文本变为“释放,返回宝贝详情”,此时松开手指,页面又滚动到第一部分的尾部。

    taobao.gif

    实现

    在自己写的demo中,第一部分是个tableView,展示商品基本信息。第二部分是个webView,展示商品图文详情。
    第一步首先加载需要的视图。主要是第一部分的tableView和第二部分的webView,还有第二部分顶部显示上拉返回文本提示的headLab。为了节省资源,其实可以在上拉触发时再加载第二部分视图的,但是这里仅作示例,所以并没有懒加载。

    - (void)loadContentView
    {
        // first view
        [self.contentView addSubview:self.tableView];
        
        // second view
        [self.contentView addSubview:self.webView];
        
        UILabel *hv = self.headLab;
        // headLab
        [self.webView addSubview:hv];
        [self.headLab bringSubviewToFront:self.contentView];
    }
    
    
    - (UILabel *)headLab
    {
        if(!_headLab){
            _headLab = [[UILabel alloc] init];
            _headLab.text = @"上拉,返回详情";
            _headLab.textAlignment = NSTextAlignmentCenter;
            _headLab.font = FONT(13);
            
        }
        
        _headLab.frame = CGRectMake(0, 0, PDWidth_mainScreen, 40.f);
        _headLab.alpha = 0.f;
        _headLab.textColor = PDColor_button_Gray;
    
        
        return _headLab;
    }
    
    
    - (UITableView *)tableView
    {
        if(!_tableView){
            _tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, PDWidth_mainScreen, self.contentView.bounds.size.height) style:UITableViewStylePlain];
            //    _tableView.contentSize = CGSizeMake(PDWidth_mainScreen, 800);
            _tableView.dataSource = self;
            _tableView.delegate = self;
            _tableView.rowHeight = 40.f;
            UILabel *tabFootLab = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, PDWidth_mainScreen, 60)];
            tabFootLab.text = @"继续拖动,查看图文详情";
            tabFootLab.font = FONT(13);
            tabFootLab.textAlignment = NSTextAlignmentCenter;
    //        tabFootLab.backgroundColor = PDColor_Orange;
            _tableView.tableFooterView = tabFootLab;
        }
        
        return _tableView;
    }
    
    
    - (UIWebView *)webView
    {
        if(!_webView){
            _webView = [[UIWebView alloc] initWithFrame:CGRectMake(0, _tableView.contentSize.height, PDWidth_mainScreen, PDHeight_mainScreen)];
            _webView.delegate = self;
            _webView.scrollView.delegate = self;
            [_webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://www.baidu.com"]]];
        }
        
        return _webView;
    }
    

    然后实现滚动视图UIScrollView的代理方法,在里面完成滚动到达临界值后,触发翻页动画的处理。包括了上拉翻到第二页和下拉翻回第一页两部分,即要在该方法里通过判断scrollView的类型做相应的处理。

    #pragma mark ---- scrollView delegate
    
    -(void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
    {
        CGFloat offsetY = scrollView.contentOffset.y;
        
        if([scrollView isKindOfClass:[UITableView class]]) // tableView界面上的滚动
        {
            // 能触发翻页的理想值:tableView整体的高度减去屏幕本省的高度
            CGFloat valueNum = _tableView.contentSize.height -PDHeight_mainScreen;
            if ((offsetY - valueNum) > _maxContentOffSet_Y)
            {
                [self goToDetailAnimation]; // 进入图文详情的动画
            }
        }
        
        else // webView页面上的滚动
        {
            NSLog(@"-----webView-------");
            if(offsetY<0 && -offsetY>_maxContentOffSet_Y)
            {
                [self backToFirstPageAnimation]; // 返回基本详情界面的动画
            }
        }
    }
    
    

    再看看两个翻页的动画,其实很简单,就是移动它们的位置。

    // 进入详情的动画
    - (void)goToDetailAnimation
    {
        [UIView animateWithDuration:0.3 delay:0.0 options:UIViewAnimationOptionLayoutSubviews animations:^{
            _webView.frame = CGRectMake(0, 0, PDWidth_mainScreen, PDHeight_mainScreen);
            _tableView.frame = CGRectMake(0, -self.contentView.bounds.size.height, PDWidth_mainScreen, self.contentView.bounds.size.height);
        } completion:^(BOOL finished) {
            
        }];
    }
    
    
    // 返回第一个界面的动画
    - (void)backToFirstPageAnimation
    {
        [UIView animateWithDuration:0.3 delay:0.0 options:UIViewAnimationOptionLayoutSubviews animations:^{
            _tableView.frame = CGRectMake(0, 0, PDWidth_mainScreen, self.contentView.bounds.size.height);
            _webView.frame = CGRectMake(0, _tableView.contentSize.height, PDWidth_mainScreen, PDHeight_mainScreen);
            
        } completion:^(BOOL finished) {
            
        }];
    }
    

    然后还有个在第二页下拉时屏幕顶部的文本提示的动画呢。这个我我们通过KVO来监听webViewscrollView的偏移量,只要其偏移量发生变化,便会实时执行KVO的代理方法,然后我们在方法内根据其偏移量的变动完成动画即可(随着偏移量变大字体变得非透明,达到某个临界点后,字体变为红色,文本内容也变为“释放,返回详情”)。

    开始监听webView滚动的偏移量

        // 开始监听_webView.scrollView的偏移量
        [_webView.scrollView addObserver:self forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil];
    

    在KVO的代理方法里,根据偏移量完成提示文本的动画

    - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context
    {
        if(object == _webView.scrollView && [keyPath isEqualToString:@"contentOffset"])
        {
            NSLog(@"----old:%@----new:%@",change[@"old"],change[@"new"]);
            [self headLabAnimation:[change[@"new"] CGPointValue].y];
        }else
        {
            [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
        }
        
    }
    

    提示文本的动画的实现代码:

    // 头部提示文本动画
    - (void)headLabAnimation:(CGFloat)offsetY
    {
        _headLab.alpha = -offsetY/60;
        _headLab.center = CGPointMake(PDWidth_mainScreen/2, -offsetY/2.f);
        // 图标翻转,表示已超过临界值,松手就会返回上页
        if(-offsetY>_maxContentOffSet_Y){
            _headLab.textColor = [UIColor redColor];
            _headLab.text = @"释放,返回详情";
        }else{
            _headLab.textColor = PDColor_button_Gray;
            _headLab.text = @"上拉,返回详情";
        }
    }
    

    demo的最终效果:

    taobaoDemo.gif

    相关文章

      网友评论

      • 7acea3f37d53:请问有demo吗?
      • 红芭乐每日C:请问这个实现,最底层的容器是什么
      • 毛豆家的老疙瘩:返回上个页面崩溃 是因为没有移除观察者
        dealloc中 如下代码
        [self.downWeb.scrollView removeObserver:self forKeyPath:@"contentOffset"];
      • PGOne爱吃饺子:大哥 怎么不给个demo看一下啊
      • 水寒不知:为什么webview你的y写成tableview的contentsize。直接写屏幕的高度就行了
      • 西西可西:麻烦问一下,tableView上拉的时候底部的webView也可以上移吗?
      • fe4a5edc73de:按照你的写了demo,返回上一个控制器会奔溃,有什么办法吗?
      • 47200923d724:楼主,可否发一份demo给我呢,47991303@qq.com,先谢谢了 :blush:
      • 我有一只小毛驴_从来都不骑:我想问你一下 你那是在 那个位置 监听webView滚动的偏移量 的
        Wang66:@老兵蛋 在webView创建之后就可以。
      • 1ccf27ae0981:@Wang66, 根据你的博客代码,我整理出一个简单的demo,如果有兴趣的话,指导一下,供大家学习参考,谢谢。
        github地址:https://github.com/qing-song/DragLayoutDemo
      • 羞答答不肯把头抬:按你的方法写的 但是有明显卡顿
        5a38f7481378:我这边按楼主思路实现了, 完全不卡顿, 楼主只是抛砖引玉, 代码别全搬.
        Wang66:@羞答答不肯把头抬 你好,找到卡顿的原因了吗?
      • 侠客不带刀:// 开始监听_webView.scrollView的偏移量
        [_webView.scrollView addObserver:self forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil];
        这个方法放到哪里?viewDidLoad 里面吗?
      • 不留名的黄子嘉:如果淘宝像你这样实现 早就死了… push动画
        Wang66:@WilliamChou_ 崩溃是不是没移除观察。
        WilliamChou_:@Wang66 大神楼主~~怎么解决奔溃的?返回页面会崩
        Wang66:@不留名的黄子嘉 什么push动画
      • WilliamChou_:大神 , 返回上一个界面会 崩溃 ,求解决~~拜托!!
        Wang66:@WilliamChou_ 解决了没?
      • 肖无情:楼主,你好,问个问题:第二页使用的webview 如果我点击产品参数,这个界面该怎么切换?我遇见这个问题了,求指教
        Wang66:@肖无情 第二页是webview,那这些应该是前端写的web
        肖无情:@Wang66 淘宝界面第二页有商品详情,产品参数,店铺推荐,这三个选项
        Wang66:@肖无情 什么产品参数?
      • ITxiansheng:淘宝的有手势监控,手势end的时候才会切换
        Wang66:@ITxiansheng哦哦,原来如此,这样更好。
      • iOSNoteByNiu:大神为什么这样判断呢,还请指教
      • iOSNoteByNiu:你好,请教个问题,博客中的这个判断if ((offsetY - valueNum) > _maxContentOffSet_Y)有什么作用呢,大于号左边的始终是大于0的,还请大神指教
        iOSNoteByNiu:@Wang66 嗯,原来如此,谢谢
        Wang66:@veryGood valueNum的值是_myTableView.contentSize.height -PDHeight_mainScreen,表示该界面tableView滑动到底部时所要滑过的偏移距离。offsetY表示的是当前所滑动的偏移距离。 如果这么写:if(offsetY>valueNum),代表只要滑动到该界面底部稍过一点点就触发;而这么写:if ((offsetY - valueNum) > _maxContentOffSet_Y代表不仅要滑到界面底部,还要再滑动_maxContentOffSet_Y的距离才会触发。
      • 夜冰雨:你好,麻烦问一下 PDHeight_mainScreen 这个数值是多少

        Wang66:@夜冰雨 PDHeight_mainScreen 和PDWidth_mainScreen分别表示设备屏幕的高和宽。
      • 雪_晟:大神,根据你的代码片段写了个 demo ,研究下,谢谢
        雪_晟:@M了个K 有demo啊 找到没 我列出来了
        哈哈大笑呼呼呼呼:@miss李manman 你好能给个demo吗 我也用到了这个谢谢 1358836531@qq.com
        夜冰雨:@miss李manman 亲 能将你的demo 供学习一下吗?763876255@QQ.com
      • somesOne:你好,请问你的contenView是什么 ?
        向钱冲啊:@Wang66 所有界面放在一个自定义view上,作用好处有哪些呢?除了大改需求时候,界面复用还有其他么?
        somesOne:@Wang66 好的,谢谢 。另外我发觉你这边不移除观察者,退出界面的时候奔溃了 .
        Wang66:@somesOne self.contentView就相当于self.view。公司的项目所有的界面是放在自定义的contentView上,而不是VC的自带的view上。
      • love_tableView:上拉继续查看的时候,这个_maxContentOffSet_Y 值是什么?怎么得到的?
        7acea3f37d53:有demo吗?可以发一份我吗?461014454@qq.com
        Wang66:@love_tableView 这个是个固定值,表示拉动多大距离触发翻页
      • 快乐的wocao666:求dome结构 190169557@qq.com 谢谢
      • minjing_lin:不错,参考
      • 刘了个二:兄弟有demo可以发一份吗?353796440@qq.com,赞已点,谢了!
      • _thor:点个赞!
      • 我想走走:兄弟有demo吗能发一份不,1240334911@qq.com
        2721b6a72b5c: @Wang66 嗯嗯😊,好的,没关系,谢谢你的文章!!
        Wang66:@爱吃桃子的小企鹅 抱歉…我没demo。当时写好发文后没刻意保存,现在没有了…
        2721b6a72b5c:@峰峰爱码 你好,作者有没有发demo给你?? , 我也想学习一下
      • 我为双鱼狂:有demo吗???想借鉴
      • 叼奶嘴打天下:不错的样子
      • 幻想无极:加油
        幻想无极:@谢谢生活 :joy:
        谢谢生活:又看到你了,大神。
        Wang66:@幻想_无极 谢谢…加油:fist:
      • 7d2ce475c51f:不错,继续努力!
        Wang66:@Vision_n君 谢谢:stuck_out_tongue_winking_eye:,你是我忠实的读者啊,哈哈

      本文标题:仿淘宝上拉进入详情页交互的实现

      本文链接:https://www.haomeiwen.com/subject/dcotettx.html