先看下效果:
首先需要构造一个header部分,header部分分为固定header和滑动header,滑动header采用横向scrollview实现:
private void bindHeader(){ headerLiearLayout = new LinearLayout(context); headerLiearLayout.setOrientation(HORIZONTAL); LinearLayout.LayoutParams params = new LayoutParams(dp2px(75),rowHeight); params.gravity = Gravity.CENTER; for (String str:fixedList){ TextView tv = new TextView(context); tv.setText(str); tv.setTextColor(Color.WHITE); tv.setGravity(Gravity.CENTER); headerLiearLayout.addView(tv,params); } rightHeader = new LinearLayout(context); for(String str:movedList){ TextView tv = new TextView(context); tv.setText(str); tv.setTextColor(Color.WHITE); tv.setGravity(Gravity.CENTER); rightHeader.addView(tv,params); } headerLiearLayout.addView(rightHeader); addView(headerLiearLayout); }
下面列表部分使用listview:
private void buildListView(){ movableLayout = new LinearLayout(context); LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT); listView = new ListView(context); movableLayout.setLayoutParams(params); listView.setBackgroundColor(0xff9f9f9f); listView.setLayoutParams(params); movableLayout.addView(listView,params); addView(movableLayout,params); }
布局模式完成,现在关键是如何实现横向滑动,且只是部分内容横向滑动。
由于我们自己需要主动去滑动,因此我们需要监听滑动事件,并能区分是横向动作还是竖直动作,如果是竖直动作的话只需要交给listview实现就可以了,横向则需要我们自己主动去滑动部分子view,以下为事件的拦截及处理机制:
@Override public boolean onInterceptTouchEvent(MotionEvent ev) { int action = ev.getAction(); if(action == MotionEvent.ACTION_MOVE && (mTouchState != TOUCH_STATE_RESET)){ return true; } int x = (int) ev.getX(); int y = (int) ev.getY(); switch (action){ case MotionEvent.ACTION_DOWN: lastX = x; lastY = y; mTouchState = scroller.isFinished()?TOUCH_STATE_RESET:TOUCH_STATE_SCRONING; break; case MotionEvent.ACTION_MOVE: int deltaX = (int)Math.abs(lastX - x); int deltaY = (int)Math.abs(lastY - y); if(deltaX > deltaY ){ mTouchState = TOUCH_STATE_SCRONING; } break; case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_UP: mTouchState = TOUCH_STATE_RESET; break; } return mTouchState != TOUCH_STATE_RESET; } @Override public boolean onTouchEvent(MotionEvent event) { int action = event.getAction(); int x = (int)event.getX(); if (velocityTracker == null) { velocityTracker = VelocityTracker.obtain(); } velocityTracker.addMovement(event); switch (action){ case MotionEvent.ACTION_DOWN: lastX = x; break; case MotionEvent.ACTION_MOVE: int deltaX = (int)(lastX - x); lastX = x; if(scroller != null && rightHeader != null){ scroller.startScroll((int)(rightHeader.getScrollX()),0,deltaX,0,0); invalidate(); } break; case MotionEvent.ACTION_UP: final VelocityTracker vt = velocityTracker; vt.computeCurrentVelocity(1000); int velocityX = (int) vt.getXVelocity(); int max = rightHeader.getChildAt(0).getWidth() * rightHeader.getChildCount() - rightHeader.getWidth(); scroller.fling(rightHeader.getScrollX(),0,-velocityX,0,0,max,0,0); invalidate(); if (velocityTracker != null) { velocityTracker.recycle(); velocityTracker = null; } mTouchState = TOUCH_STATE_RESET; break; case MotionEvent.ACTION_CANCEL: mTouchState = TOUCH_STATE_RESET; break; } return true; }
Scroll 是一个滚动控制器,在这里需要用它来实现横向滑动。注意startscroll和fling函数,看名字就知道了这里不多述,重要的一点是调用了该函数后,主动刷新view会条用completscroll函数(不明白的可以查看view的刷新机制),在这个函数中是实现真正的滑动部分:
@Override public void computeScroll() { if(scroller.computeScrollOffset()){ int scrollX = scroller.getCurrX(); final int maxX = rightHeader.getChildAt(0).getWidth() * rightHeader.getChildCount() - rightHeader.getWidth(); scrollX = Math.max(0,scrollX); scrollX = Math.min(maxX,scrollX); rightHeader.scrollTo(scrollX,0); scrollChildTo(scrollX); } }
在scrollchildTo函数中完成对listview中各个child的部分view的横向滑动:
protected void scrollChildTo(int mScrollX) { if(listView != null) { View temp = null; int nChildCount = listView.getChildCount(); for(int i = 0; i < nChildCount; i++) { temp = listView.getChildAt(i); int size = ((ViewGroup) temp).getChildCount(); for(int j = 0;j < size;j ++){ View item = ((ViewGroup) temp).getChildAt(j); if(item instanceof LinearLayout) { item.scrollTo(mScrollX, 0); } } } } }
这里的item布局可以看出,横向滚动部分使用linearlayout部分包裹,因此只需要让该view滚动即可.
最后就是适配器的处理了,基本上adapter跟普通的一样,不过有一点需要注意的是view的重用机制会造成最后一条滚动异常,我们需要加上一段矫正代码:
private void adjustMoved(View view) { View moveView = (View) view.findViewById(R.id.moveLayout); int moveX1 = moveView.getScrollX(); int moveX2 = ajustView.getScrollX(); if(moveX1 != moveX2){ moveView.scrollTo(ajustView.getScrollX(),0); } }
基本实现基本完成了,剩下的事情就是填充数据展示之类的。
抱歉,公司不能传代码,如果有需要的可以给我留言,我重新写一个完整的。
相关推荐
微信小程序原生方式实现列表的横向滑动的两种方法: 效果图: 方式一:简单样式实现 父元素设置: white-space:nowrap;//不换行 overflow-x: auto;子元素设置: display:inline-block; 方式二:scroll-view 标签 + ...
自定义控件实现横向滑动背景图视差效果
横向滑动的HorizontalScrollView嵌套GridView,实现单行横向滑动的Demo
主要为大家详细介绍了RecyclerView+CardView实现横向卡片式滑动效果,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
可以实现横向分页和纵向分页,主要用的是安卓原生实现
一个可以横向滑动的gridview
android横向滚动列表,ListView横向展示
Android_横向滑动实现的比较 Android 横向滑动 viewflipper viewpager
ViewPager横向滑动菜单的实现Demo
ViewPager+GridView实现宫格横向分页滑动切换
Android横向listview,列表左右可滑动,作为参考,很实用
android导航菜单横向左右滑动并和下方的控件实现联动
GridView的横向滑动,非常简单,一目了然,不用计算复杂的GridView长度,而是直接设置横向滑动即可,可供参考;
通过在HorizontalScrollView中嵌套ListView控件,实现ListView的水平滑动效果
单行横向滑动的日历控件,可设置起始结束日期
UIScrollView横向移动, 可实现左右滑动查看信息
android 横向滑动翻页效果 实例
UICollectionViewFlowLayout 流式布局我们常用,但他不支持横向排列并横向滑动,我们只有自定义布局,自己设置cell的排列逻辑,笔者试过使用iOS 9的重排API,发现你如果重写layout,底层重排逻辑你没法重写,你也不...
Android RecyclerView横向滑动+自动轮播(一款值得你借鉴的Demo)
本例子是单行横向滑动日历,只显示一行日历,利用ViewFlipper动态添加和删除GridView达到资源合理利用,滑动过程顺畅