android listview 滑动条显示_Android自定义ListView高仿一个QQ可拖拽列表的实现

我们做一些好友列表或者商品列表的时候,居多的需求可能就是需要列表拖拽了,而我们选择了ListView,也是因为使用ListView太久远了,导致对他已经有浓厚的感情了,我们之前也是写过几篇关于ListView的博文

  • Android实训案例(三)——实现时间轴效果的ListView,加入本地存储,实现恋爱日记的效果!
  • Android高级控件(一)——ListView绑定CheckBox实现全选,增加和删除等功能
  • Android高级控件(五)——如何打造一个企业级应用对话列表,以QQ,微信为例

而今天我们就来实现以下课拖拽的方案,大家可以借鉴以下

我们大致的思路,其实是这样子的,也是我的设想,我们可以先去实现一个简单的ListView的数据,但是他的Adapter,我们可以用系统封装好的,然后传递进去一个实体类,最后自定义一个listview去操作,所以我们先把准备的工作做好,比如?

list_item.xml

<?xml version="1.0" encoding="utf-8"?>

这就只有一个头像和一句话了,然后我们把实体类也给写完了

DragBean

package com.liuguilin.draglistviewsample.entity;/* * 项目名: DragListViewSample  * 包名: com.liuguilin.draglistviewsample.entity * 文件名: DragBean * 创建者: LGL * 创建时间: 2016/8/29 22:49 * 描述: 实体类 */public class DragBean { private int ivId; private String text; public DragBean() { } public DragBean(int ivId, String text) { this.ivId = ivId; this.text = text; } public int getIvId() { return ivId; } public String getText() { return text; }}

ok,其实很简单,id是图片,然后是文本,这样我们就可以来实现一个Adapter了,这里我用的是ArrayAdapter这样能让我们插入和删除很轻松

DragAdapter

package com.liuguilin.draglistviewsample.adapter;/* * 项目名: DragListViewSample  * 包名: com.liuguilin.draglistviewsample.adapter * 文件名: DragAdapter * 创建者: LGL * 创建时间: 2016/8/29 22:41 * 描述: 拖拽列表的数据源 */import android.content.Context;import android.view.View;import android.view.ViewGroup;import android.widget.ArrayAdapter;import android.widget.ImageView;import android.widget.TextView;import com.liuguilin.draglistviewsample.R;import com.liuguilin.draglistviewsample.entity.DragBean;import java.util.List;public class DragAdapter extends ArrayAdapter { /** * 构造方法 * * @param context * @param mList */ public DragAdapter(Context context, List mList) { super(context, 0, mList); } /** * 实现View * * @param position * @param convertView * @param parent * @return */ @Override public View getView(int position, View convertView, ViewGroup parent) { View view; ViewHolder viewHolder; if (convertView == null) { view = View.inflate(getContext(), R.layout.list_item, null); viewHolder = new ViewHolder(); viewHolder.imageView = (ImageView) view .findViewById(R.id.iv_logo); viewHolder.textView = (TextView) view.findViewById(R.id.textView); view.setTag(viewHolder); } else { view = convertView; viewHolder = (ViewHolder) view.getTag(); } viewHolder.imageView.setImageResource(getItem(position).getIvId()); viewHolder.textView.setText(getItem(position).getText()); return view; } /** * 缓存 */ static class ViewHolder { ImageView imageView; TextView textView; }}

好的,其实到这里,他就是一个最普通的ListView了,我们给他填充点数据

MainActivity

package com.liuguilin.draglistviewsample;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import com.liuguilin.draglistviewsample.adapter.DragAdapter;import com.liuguilin.draglistviewsample.entity.DragBean;import com.liuguilin.draglistviewsample.view.DragListView;import java.util.ArrayList;import java.util.List;public class MainActivity extends AppCompatActivity { //列表 private DragListView mListView; //数据 private List mList = new ArrayList<>(); //数据源 private DragAdapter adapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); } /** * 初始化View */ private void initView() { mListView = (DragListView) findViewById(R.id.mListView); //新增數據 for (int i = 0; i < 30; i++) { DragBean bean = new DragBean(R.mipmap.ic_launcher, "刘某人程序员" + i); mList.add(bean); } //初始化数据源 adapter = new DragAdapter(this,mList); mListView.setAdapter(adapter); }}

现在可以看看实际的效果了

2b7970073596471681527f7cf7575d2c

现在我们可以重写我们的ListView了

我们首先拦截他的事件

 /** * 获取触点所在条目的位置 * 获取选中条目的图片 * 事件的拦截机制 * * @param ev * @return */ @Override public boolean onInterceptTouchEvent(MotionEvent ev) { //识别动作 switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: //获取触点的坐标 int x = (int) ev.getX(); int y = (int) ev.getY(); //这样就可以计算我按到哪个条目上了 mStartPosition = mEndPosition = pointToPosition(x, y); //判断触点是否在logo的区域 ViewGroup itemView = (ViewGroup) getChildAt(mStartPosition - getFirstVisiblePosition()); //记录手指在条目中的相对Y坐标 dragPoint = y - itemView.getTop(); //ListView在屏幕中的Y坐标 dragOffset = (int) (ev.getRawY() - y); //拖动的图标 View dragger = itemView.findViewById(R.id.iv_logo); //判断触点是否在logo区域 if (dragger != null && x < dragger.getRight() + 10) { //定义ListView的滚动条目 //上 upScroll = getHeight() / 3; //下 downScroll = getHeight() * 2 / 3; //获取选中的图片/截图 itemView.setDrawingCacheEnabled(true); //获取截图 Bitmap bitMap = itemView.getDrawingCache(); //图片滚动 startDrag(bitMap, y); } break; } //还会传递事件到子View return false; }

获取到他的position之后我们直接截图,并且显示我们的window,这里做的事情就比较多了我们还要判断是否点击的是头像才去显示window

/**

* 图片在Y轴,也就是上下可滚动

*

* @param bitMap

* @param y

*/

private void startDrag(Bitmap bitMap, int y) {

//窗体仿照

wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);

//设置窗体参数

lParams = new WindowManager.LayoutParams();

//设置宽高

lParams.width = WindowManager.LayoutParams.WRAP_CONTENT;

lParams.height = WindowManager.LayoutParams.WRAP_CONTENT;

//属性

lParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE

| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE

| WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;

//设置半透明

lParams.alpha = 0.8f;

//设置居中

lParams.gravity = Gravity.TOP;

//设置xy

lParams.x = 0;

lParams.y = y-dragPoint + dragOffset;

//属性

lParams.format = PixelFormat.TRANSLUCENT;

//设置动画

lParams.windowAnimations = 0;

//图片

dragImageView = new ImageView(getContext());

//设置截图

dragImageView.setImageBitmap(bitMap);

//添加显示窗体

wm.addView(dragImageView, lParams);

}

好的,我们初始化一下window,光显示还不行呢,我们还要可以滑动,怎么监听?onTouchEvent的ACTION_MOVE事件是可以做到的

 /** * 触摸事件 * * @param ev * @return */ @Override public boolean onTouchEvent(MotionEvent ev) { //错误的位置 if (dragImageView != null && mEndPosition != INVALID_POSITION) { //在滑动事件中控制上下滑动 switch (ev.getAction()) { case MotionEvent.ACTION_MOVE: //直接获取到Y坐标进行移动 int moveY = (int) ev.getY(); doDrag(moveY); break; //停止拖动成像 case MotionEvent.ACTION_UP: int upY = (int) ev.getY(); stopDrag(); onDrag(upY); break; } } //拦截到事件 return true; }

我们在移动的时候不断的去更新他的位置

/** * 控制窗体移动 * * @param moveY */ private void doDrag(int moveY) { if (dragImageView != null) { lParams.y = moveY - dragPoint + dragOffset; wm.updateViewLayout(dragImageView, lParams); } //判断移动到分割线 返回-1 int tempLine = pointToPosition(0, moveY); //我们处理他 if (tempLine != INVALID_POSITION) { //只要你不移动到分割线 我才处理 mEndPosition = tempLine; } //拖拽时滚动、滚动速度 int scrollSpeed = 0; //上滚 if (moveY < upScroll) { scrollSpeed = 10; //下滚 } else if (moveY > downScroll) { scrollSpeed = -10; } //开始滚动 if (scrollSpeed != 0) { //计算条目的Y坐标 int dragItemY = getChildAt(mEndPosition - getFirstVisiblePosition()).getTop(); //当前速度 int dy = dragItemY + scrollSpeed; //设置 setSelectionFromTop(mEndPosition, dy); } }

当你移动完成之后,我就可以停止你的window体了

 /** * 停止的位置 */ private void stopDrag() { //直接移除窗体 if (dragImageView != null) { wm.removeView(dragImageView); dragImageView = null; } }

这样,我就直接拼接你的position达到一个拖拽的效果

 /** * 最终开始成像 * * @param upY */ private void onDrag(int upY) { //分割线的处理 //判断移动到分割线 返回-1 int tempLine = pointToPosition(0, upY); //我们处理他 if (tempLine != INVALID_POSITION) { //只要你不移动到分割线 我才处理 mEndPosition = tempLine; } /** * 你在最上方就直接落在第一个最下方就直接最下面一个 */ //上边界处理 if (upY < getChildAt(1).getTop()) { mEndPosition = 1; //下边界处理 } else if (upY > getChildAt(getChildCount() - 1).getTop()) { mEndPosition = getAdapter().getCount() - 1; } //开始更新item顺序 if (mEndPosition > 0 && mEndPosition < getAdapter().getCount()) { DragAdapter adapter = (DragAdapter) getAdapter(); //删除原来的条目 adapter.remove(adapter.getItem(mStartPosition)); //更新 adapter.insert(adapter.getItem(mStartPosition), mEndPosition); } }

全部代码贴上

DragListView

package com.liuguilin.draglistviewsample.view;/* * 项目名: DragListViewSample  * 包名: com.liuguilin.draglistviewsample.view * 文件名: DragListView * 创建者: LGL * 创建时间: 2016/8/29 20:50 * 描述: 自定义高仿QQ列表可拖拽的ListView */import android.content.Context;import android.graphics.Bitmap;import android.graphics.PixelFormat;import android.util.AttributeSet;import android.view.Gravity;import android.view.MotionEvent;import android.view.View;import android.view.ViewGroup;import android.view.WindowManager;import android.widget.ImageView;import android.widget.ListView;import com.liuguilin.draglistviewsample.R;import com.liuguilin.draglistviewsample.adapter.DragAdapter;public class DragListView extends ListView { //按下选中的position private int mStartPosition; //需要达到的position private int mEndPosition; //手指在条目中的相对Y坐标 private int dragPoint; //ListView在屏幕中的Y坐标 private int dragOffset; //上 private int upScroll; //下 private int downScroll; //窗体 private WindowManager wm; //显示的截图 private ImageView dragImageView; //窗体参数 private WindowManager.LayoutParams lParams; //构造方法 public DragListView(Context context, AttributeSet attrs) { super(context, attrs); } /** * 获取触点所在条目的位置 * 获取选中条目的图片 * 事件的拦截机制 * * @param ev * @return */ @Override public boolean onInterceptTouchEvent(MotionEvent ev) { //识别动作 switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: //获取触点的坐标 int x = (int) ev.getX(); int y = (int) ev.getY(); //这样就可以计算我按到哪个条目上了 mStartPosition = mEndPosition = pointToPosition(x, y); //判断触点是否在logo的区域 ViewGroup itemView = (ViewGroup) getChildAt(mStartPosition - getFirstVisiblePosition()); //记录手指在条目中的相对Y坐标 dragPoint = y - itemView.getTop(); //ListView在屏幕中的Y坐标 dragOffset = (int) (ev.getRawY() - y); //拖动的图标 View dragger = itemView.findViewById(R.id.iv_logo); //判断触点是否在logo区域 if (dragger != null && x < dragger.getRight() + 10) { //定义ListView的滚动条目 //上 upScroll = getHeight() / 3; //下 downScroll = getHeight() * 2 / 3; //获取选中的图片/截图 itemView.setDrawingCacheEnabled(true); //获取截图 Bitmap bitMap = itemView.getDrawingCache(); //图片滚动 startDrag(bitMap, y); } break; } //还会传递事件到子View return false; } /** * 图片在Y轴,也就是上下可滚动 * * @param bitMap * @param y */ private void startDrag(Bitmap bitMap, int y) { //窗体仿照 wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE); //设置窗体参数 lParams = new WindowManager.LayoutParams(); //设置宽高 lParams.width = WindowManager.LayoutParams.WRAP_CONTENT; lParams.height = WindowManager.LayoutParams.WRAP_CONTENT; //属性 lParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON; //设置半透明 lParams.alpha = 0.8f; //设置居中 lParams.gravity = Gravity.TOP; //设置xy lParams.x = 0; lParams.y = y-dragPoint + dragOffset; //属性 lParams.format = PixelFormat.TRANSLUCENT; //设置动画 lParams.windowAnimations = 0; //图片 dragImageView = new ImageView(getContext()); //设置截图 dragImageView.setImageBitmap(bitMap); //添加显示窗体 wm.addView(dragImageView, lParams); } /** * 触摸事件 * * @param ev * @return */ @Override public boolean onTouchEvent(MotionEvent ev) { //错误的位置 if (dragImageView != null && mEndPosition != INVALID_POSITION) { //在滑动事件中控制上下滑动 switch (ev.getAction()) { case MotionEvent.ACTION_MOVE: //直接获取到Y坐标进行移动 int moveY = (int) ev.getY(); doDrag(moveY); break; //停止拖动成像 case MotionEvent.ACTION_UP: int upY = (int) ev.getY(); stopDrag(); onDrag(upY); break; } } //拦截到事件 return true; } /** * 最终开始成像 * * @param upY */ private void onDrag(int upY) { //分割线的处理 //判断移动到分割线 返回-1 int tempLine = pointToPosition(0, upY); //我们处理他 if (tempLine != INVALID_POSITION) { //只要你不移动到分割线 我才处理 mEndPosition = tempLine; } /** * 你在最上方就直接落在第一个最下方就直接最下面一个 */ //上边界处理 if (upY < getChildAt(1).getTop()) { mEndPosition = 1; //下边界处理 } else if (upY > getChildAt(getChildCount() - 1).getTop()) { mEndPosition = getAdapter().getCount() - 1; } //开始更新item顺序 if (mEndPosition > 0 && mEndPosition < getAdapter().getCount()) { DragAdapter adapter = (DragAdapter) getAdapter(); //删除原来的条目 adapter.remove(adapter.getItem(mStartPosition)); //更新 adapter.insert(adapter.getItem(mStartPosition), mEndPosition); } } /** * 停止的位置 */ private void stopDrag() { //直接移除窗体 if (dragImageView != null) { wm.removeView(dragImageView); dragImageView = null; } } /** * 控制窗体移动 * * @param moveY */ private void doDrag(int moveY) { if (dragImageView != null) { lParams.y = moveY - dragPoint + dragOffset; wm.updateViewLayout(dragImageView, lParams); } //判断移动到分割线 返回-1 int tempLine = pointToPosition(0, moveY); //我们处理他 if (tempLine != INVALID_POSITION) { //只要你不移动到分割线 我才处理 mEndPosition = tempLine; } //拖拽时滚动、滚动速度 int scrollSpeed = 0; //上滚 if (moveY < upScroll) { scrollSpeed = 10; //下滚 } else if (moveY > downScroll) { scrollSpeed = -10; } //开始滚动 if (scrollSpeed != 0) { //计算条目的Y坐标 int dragItemY = getChildAt(mEndPosition - getFirstVisiblePosition()).getTop(); //当前速度 int dy = dragItemY + scrollSpeed; //设置 setSelectionFromTop(mEndPosition, dy); } }}

然后我们引用

layout_main.xml

<?xml version="1.0" encoding="utf-8"?>

对了,别忘记了添加窗体的权限哦

  

做完这一系列事情之后,就觉得这个设想其实是对的,然后我们可以尝试性的运行一下

b02351432bdf492eaa4fc71b7e69966f

运行时成功的,说明我们的设想是没有问题的,但是随着而来的,也是诸多的bug,所以呢,这也只是思想的参考,不过这些bug我有时间野就修复一下,应该是可以的,好的,本篇博文就先到这里!

有兴趣的加群:555974449

DragListViewSample:http://download.csdn.net/detail/qq_26787115/9616355

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值