Android 横向带有吸附效果的横向拖动控件(效果同纵向下拉刷新ListView)
来源:互联网 发布:mox反应堆 知乎 编辑:程序博客网 时间:2024/04/30 05:11
先上一张效果图
中间的横向拖动就是我们要做的效果。
一、实现思路
仔细观察不难发现,该拖动view与listview的下拉刷新的效果很类似,手指拖动的时候显示隐藏的view,手指放开自动回弹。只不过区别就是一个横向一个纵向
下拉刷新的实现思路如下:
自定义一个布局继承自LinearLayout,然后在这个布局中加入下拉头和ListView这两个子元素,并让这两个子元素纵向排列。初始化的时候,让下拉头向上偏移出屏幕,这样我们看到的就只有ListView了。然后对ListView的touch事件进行监听,如果当前ListView已经滚动到顶部并且手指还在向下拉的话,那就将下拉头显示出来,松手后进行刷新操作,并将下拉头隐藏。原理如图所示:
我们要实现的效果跟下拉刷新基本一样,只不过是方向是横向而已。如图
二、具体实现
首先我们要先自定义一个LinearLayout,然后在布局中加入隐藏头和剩余部分
布局文件如下:
<com.boohee.myview.HorizontalDragLinearLayout android:id="@+id/main_hori_scroll_ll" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/white" android:baselineAligned="false" android:clickable="true" android:descendantFocusability="blocksDescendants" android:orientation="horizontal"> <!--添加一层处理左右拖动时的移动--> <LinearLayout android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="wrap_content" > ...........<pre name="code" class="java"><span style="white-space:pre"></span><!--此处添加 剩余显示的部分--></LinearLayout> </com.boohee.myview.HorizontalDragLinearLayout>自定义的LinearLayout,初始化部分:
private Context context; //需要隐藏的view private TextView headerView; /** * 是否已加载过一次layout,这里onLayout中的初始化只需加载一次 */ private boolean loadOnce; /** * 需要隐藏View的布局参数 */ private MarginLayoutParams headerLayoutParams; /** * 隐藏view的宽度 */ private int hideHeaderWidth; private float xDown; /** * 每次move的x坐标 */ private float tmpXMove; private float mFocusX = 0.f; /** * 在被判定为滚动之前用户手指可以移动的最大值。 */ private int touchSlop; /** * 头部回滚的速度 */ public static final int SCROLL_SPEED = -10; public HorizontalDragLinearLayout(Context context) { this(context, null); } public HorizontalDragLinearLayout(Context context, AttributeSet attrs) { this(context, attrs, 0); } public HorizontalDragLinearLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); setOrientation(HORIZONTAL); this.context = context; init(); } private void init() { touchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); headerView = new TextView(context); LinearLayout.LayoutParams params = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); params.gravity = Gravity.CENTER_VERTICAL; headerView.setLayoutParams(params); headerView.setTextColor(Color.BLACK); headerView.setGravity(Gravity.CENTER); this.addView(headerView, 0); } public void setHeaderText(String string){ if (headerView != null){ headerView.setText(string); } } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { super.onLayout(changed, l, t, r, b); if (headerView != null && changed && !loadOnce){ hideHeaderWidth = - headerView.getWidth(); headerLayoutParams = (MarginLayoutParams) headerView.getLayoutParams(); headerLayoutParams.leftMargin = hideHeaderWidth; headerView.setLayoutParams(headerLayoutParams); loadOnce = true; } }
初始化的时候动态添加了一个TextView,也就是我们需要隐藏的部分
在第一次onLayout布局的时候,我们根据隐藏头的宽度 调整该隐藏头的margin,使其隐藏。
然后我们需要进行拖动识别,重写onTouchEvent
@Override public boolean onTouchEvent(MotionEvent motionEvent) { //禁止父容器拦截事件 getParent().requestDisallowInterceptTouchEvent(true); switch (motionEvent.getAction()){ case MotionEvent.ACTION_DOWN: xDown = motionEvent.getRawX(); return true; case MotionEvent.ACTION_MOVE: float xMove = motionEvent.getRawX(); int distance = (int) (xMove - xDown); if (distance <= 0 && headerLayoutParams.leftMargin <= hideHeaderWidth) { return false; } if (distance < touchSlop) { return false; } //大于头部宽度不做处理 if (distance >= -hideHeaderWidth){ return true; } headerLayoutParams.leftMargin = distance + hideHeaderWidth; headerView.setLayoutParams(headerLayoutParams); tmpXMove = xMove; return true; case MotionEvent.ACTION_UP: //松手时调用隐藏头部 new HideHeaderTask().execute(); break; default: break; } return true; }
由于外层是用的viewPager+fragment进行页面切换,所以默认情况下touch事件是被viewpager消费掉的。我们要组织父控件拦截事件
getParent().requestDisallowInterceptTouchEvent(true);
其中涉及Android 的touch 分发,可以参考鸿洋大大的这篇博客点击打开链接
在move的时候得到移动的距离,然后对隐藏头设置margin,使其及该LinearLayout的其他子view跟随隐藏头一起向右移动,达到我们想要的效果
up的时候启动一个AsyncTask 动态改变隐藏头的margin,去恢复到最初始的状态,即隐藏头隐藏的状态。
/** * 隐藏头部 */ class HideHeaderTask extends AsyncTask<Void, Integer, Integer> { @Override protected Integer doInBackground(Void... params) { int leftMargin = headerLayoutParams.leftMargin; while (true) { leftMargin = leftMargin + SCROLL_SPEED; if (leftMargin <= hideHeaderWidth) { leftMargin = hideHeaderWidth; break; } publishProgress(leftMargin); sleep(10); } return leftMargin; } @Override protected void onProgressUpdate(Integer... leftMargin) { headerLayoutParams.leftMargin = leftMargin[0]; headerView.setLayoutParams(headerLayoutParams); } @Override protected void onPostExecute(Integer leftMargin) { headerLayoutParams.leftMargin = leftMargin; headerView.setLayoutParams(headerLayoutParams); } } private void sleep(int i) { try { Thread.sleep(i); } catch (InterruptedException e) { e.printStackTrace(); } }
搞定。
另外 效果中带悬浮进度的progressBar 连接在这里
0 0
- Android 横向带有吸附效果的横向拖动控件(效果同纵向下拉刷新ListView)
- 横向,纵向的3dGallery效果
- 【Android】用RecycleView实现可以横向滚动的ListView效果
- javascript 横向和纵向滚动效果
- 横向纵向下拉框
- 横向,纵向下拉菜单
- android自定义控件--横向滑动的ListView
- 带有下拉刷新功能的Listview控件
- 带有下拉刷新功能的Listview控件
- 带有下拉刷新功能的Listview控件
- android 图片横向滚动效果
- android 图片横向滚动效果
- android 图片横向滚动效果
- Android 实现横向滑动效果
- ListView下拉刷新效果
- 横向的JS相册效果
- 关于jquery-ui,页面横向纵向拖动布局的方法。
- 【WPF】ListView 大图标 横向排列效果
- O(1) 空间复杂度逆序栈和排序栈
- 如何高效的结算一个正整数中二进制表示1的个数
- iPhone开发——AFN使用总结
- Flex RemoteObject 限制远程Java对象可访问方法
- Sicily 13862. Empty Stalls
- Android 横向带有吸附效果的横向拖动控件(效果同纵向下拉刷新ListView)
- 第9课时,自测
- [leetcode]Valid Phone Numbers
- ACM 算法3-3 迷宫 程序
- fgetc fputc fgets fputs fprintf fscanf getc getchar gets putc putchar puts ungetc函数介绍
- android sdk离线安装
- python - 测量程序运行时间 + 一个对于列表的小实验
- LeetCode 191: Number of 1 Bits
- 在floodlight控制器中统计进入packed-in数量的代码