Android 自定义有速率差的联动ScrollView

这个是原创。。
项目需要实现类似京东金融首页联动滑动的效果,图如下


555.gif

第一个想到的实现方式是上面使用horizontalScrollview,下面使用Viewpager,经过尝试之后发现二者API有限,不能达到理想效果。几经折腾,最后上下都使用了自定义的RecyclerView。效果图如下


222.gif

现在来分析技术点,首先是上下联动,思路是在Recycleview的onScrolled回调方法中操作另一个Recycleview的滑动

@Override
    public void onScrolled(int dx, int dy) {
        super.onScrolled(dx, dy);
        sx = sx +dx;
        if (scrollViewListener != null && isMark) {
            scrollViewListener.onScrollChanged(this, sx, 0);
        }
    }

其中onScrollChanged方法在主页面中实现

@Override
    public void onScrollChanged(Object scrollView, int x, int y) {
        int width1 = CommonUtil.getScreenWidth(this) - DensityUtils.dip2px(this, 60);
        int width2 = CommonUtil.getScreenWidth(this);
        if (scrollView == rvHead) {
            rvFoot.setmark(false);
            rvFoot.scrollTo(x * width2 / width1, y);
        } else if (scrollView == rvFoot) {
            rvHead.setmark(false);

            rvHead.scrollTo(x * width1 / width2, y);
        }
        rvHead.setmark(true);
        rvFoot.setmark(true);
    }

上下View的滑动速率差即为上下RecyclerView中item的宽度差,上面view中item的宽度为屏幕宽度-60dp,详见对应的adapter。
由于RecyclerView中scrollTo方法没有实现,所以直接想到的是用scroolBy代替,但由于滑动回调返回的是Int值,经过速率差处理后精度丢失,得不到准确值,导致联动效果达不到,痛定思痛,最后还是自己来重写scrollTo方法

  @Override
    public void scrollTo(int x, int y) {
        scrollBy(x-sx,0);
    }

sx为自己在onScrolled方法中记录,具体见文末给出的源码
滑动之后,还要进行回调处理,以达到像viewPager那样的回弹效果,具体逻辑在自定义的RecyclerView中的回调方法onScrollStateChanged中实现

@Override
        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
            super.onScrollStateChanged(recyclerView, newState);

            if (newState == RecyclerView.SCROLL_STATE_IDLE) {
                int mmSelected;
                //当控件停止滚动时,获取可视范围第一个item的位置,滚动调整控件以使选中的item刚好处于正中间
                int firstVisiblePos = mLayoutManager.findFirstVisibleItemPosition();
                if (firstVisiblePos == RecyclerView.NO_POSITION) {
                    return;
                }
                Rect rect = new Rect();
                mLayoutManager.findViewByPosition(firstVisiblePos).getHitRect(rect);
                Log.e("left1",rect.left+"");
                if (rect.left == 0)return;
                if (Math.abs(rect.left) > mItemWidth / 2) {
                    smoothScrollBy(rect.right - DensityUtils.dip2px(getContext(), 20), 0);
                    mmSelected = firstVisiblePos + 1;
                } else {
                    smoothScrollBy(rect.left - DensityUtils.dip2px(getContext(), 20), 0);
                    mmSelected = firstVisiblePos;
                }

为了让滑动效果更为自然且支持fling效果,本项目还重写了RecyclerView的fling方法,使得每次fling都恰好能滑动整数个item,大致思路为调整fling初始速率,代码如下

@Override
    public boolean fling(int velocityX, int velocityY) {
        int v;
        int touchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
        Log.e("=========","x "+velocityX+" s "+touchSlop);
        if (Math.abs(velocityX) <= 3*touchSlop) return false;
        mPhysicalCoeff = SensorManager.GRAVITY_EARTH   // g (m/s^2)
                * 39.37f               // inch/meter
                * getContext().getResources().getDisplayMetrics().density * 160.0f                 // pixels per inch
                * 0.84f;
        int firstVisiblePos = mLayoutManager.findFirstVisibleItemPosition();
        if (firstVisiblePos == RecyclerView.NO_POSITION) {
            return false;
        }
        Rect rect = new Rect();
        mLayoutManager.findViewByPosition(firstVisiblePos).getHitRect(rect);
        double n = getSplineFlingDistance(velocityX) / mItemWidth;
        int num = Double.valueOf(n).intValue();
        if (velocityX > 0)
            v = Double.valueOf(getVelocityByDistance(num * mItemWidth + Math.abs(rect.right)- DensityUtils.dip2px(getContext(), 20))).intValue();
        else
            v = Double.valueOf(getVelocityByDistance(num * mItemWidth + Math.abs(rect.left)+ DensityUtils.dip2px(getContext(), 20))).intValue();
        if (velocityX < 0) v = -v;
        return super.fling(v, velocityY);
    }

github地址 https://github.com/meiniepan/TogetherScrollView

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,907评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,987评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,298评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,586评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,633评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,488评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,275评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,176评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,619评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,819评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,932评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,655评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,265评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,871评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,994评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,095评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,884评论 2 354

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 172,127评论 25 707
  • 【Android 控件 RecyclerView】 概述 RecyclerView是什么 从Android 5.0...
    Rtia阅读 307,511评论 27 439
  • 内容抽屉菜单ListViewWebViewSwitchButton按钮点赞按钮进度条TabLayout图标下拉刷新...
    皇小弟阅读 46,759评论 22 665
  • 有多少个无法入睡的夜里,我都会情不自禁地想起那片孩提时代的树林。我的执迷曾让我一度困惑,我常问我自己到底在迷恋它什...
    花间微语阅读 258评论 0 3
  • 清晨 铁块撞击木板 发动机轰鸣 嘶哑但还要叫喊 豆子被碾碎 儿童哭闹 …… 如果可以 我希望世界就此哑掉 用无声表...
    b2247950c6d4阅读 369评论 0 1