zoukankan      html  css  js  c++  java
  • 可拖拽的ListView

    说明: WindowManager在addView时尚未测量完成, 获取宽高都是0。 可以这样测量:

    view.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
    int width = view.getMeasuredWidth();
    1
    2
    使用getViewTreeObserver().addOnGlobalLayoutListener是布局完成后可以获取宽高;

    public class DragListView extends ListView {

    private WindowManager.LayoutParams windowParams;
    private WindowManager windowManager;
    private ImageView dragImageView;

    private int offsetScreenTop; //距离屏幕顶部的位置
    private int offsetViewTop; //手指按下位置距离item顶部的位置
    private int dragPosition;

    //上次点击按下的坐标
    private int mLastMotionX, mLastMotionY;

    private final int TOUCH_SLOP = 20;
    private Runnable mLongPressRunnable;
    private Bitmap mCurItemBmp;

    //当前是否长按状态
    private boolean mIsLongTouch;

    public DragListView(Context context) {
    super(context);
    }

    public DragListView(Context context, AttributeSet attrs) {
    super(context, attrs);

    mLongPressRunnable = new Runnable() {
    @Override public void run() {
    mIsLongTouch = true;

    startDrag(mCurItemBmp, mLastMotionY);
    }
    };
    }

    //itemview里有view处理点击事件时, 当前ListView无法收到UP或CANCEL消息
    @Override public boolean dispatchTouchEvent(MotionEvent ev) {
    if (ev.getAction() == MotionEvent.ACTION_UP
    || ev.getAction() == MotionEvent.ACTION_CANCEL) {
    removeCallbacks(mLongPressRunnable);
    stopDrag();
    }
    return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
    int x = (int) ev.getX();
    int y = (int) ev.getY();
    int rawY = (int) ev.getRawY();

    if (ev.getAction() == MotionEvent.ACTION_DOWN) {
    mLastMotionX = x;
    mLastMotionY = y;
    mIsLongTouch = false;
    stopDrag(); //复位
    removeCallbacks(mLongPressRunnable);

    int currentPostion = dragPosition = pointToPosition(x, y);

    //拖拽效果设置热区
    if (currentPostion == AdapterView.INVALID_POSITION) {
    return super.onInterceptTouchEvent(ev);
    }
    postDelayed(mLongPressRunnable, ViewConfiguration.getLongPressTimeout());

    //getChildAt是获取可见位置的item
    ViewGroup itemView = (ViewGroup) getChildAt(currentPostion - getFirstVisiblePosition());
    offsetScreenTop = rawY - y;
    offsetViewTop = y - itemView.getTop();

    itemView.setDrawingCacheEnabled(true);// 开启cache.
    mCurItemBmp = Bitmap.createBitmap(itemView.getDrawingCache());// 根据cache创建一个新的bitmap对象.
    itemView.setDrawingCacheEnabled(false);// 一定关闭cache,否则复用会出现错乱
    }
    return super.onInterceptTouchEvent(ev);
    }


    @Override
    public boolean onTouchEvent(MotionEvent ev) {
    int y = (int) ev.getY();
    int x = (int) ev.getX();
    switch (ev.getAction()) {
    case MotionEvent.ACTION_MOVE:
    if (Math.abs(mLastMotionX - x) > TOUCH_SLOP
    || Math.abs(mLastMotionY - y) > TOUCH_SLOP) {
    //滑动超过阈值时判定不是长按
    removeCallbacks(mLongPressRunnable);
    }

    if (mIsLongTouch) {
    onDrag(y);
    getChildAt(dragPosition - getFirstVisiblePosition()).setVisibility(View.INVISIBLE);
    return true; //避免列表滑动
    }
    removeCallbacks(mLongPressRunnable);
    break;
    case MotionEvent.ACTION_CANCEL:
    case MotionEvent.ACTION_UP:
    removeCallbacks(mLongPressRunnable);
    if (mIsLongTouch) {
    stopDrag();
    getChildAt(dragPosition - getFirstVisiblePosition()).setVisibility(View.VISIBLE);

    mIsLongTouch = false;
    }
    break;
    }

    return super.onTouchEvent(ev);
    }

    private void startDrag(Bitmap bm, int y) {
    int[] location = new int[2];
    getLocationInWindow(location);

    /***
    * 初始化window.
    */
    windowParams = new WindowManager.LayoutParams();
    windowParams.gravity = Gravity.TOP|Gravity.LEFT;
    windowParams.x = location[0];
    windowParams.y = y - offsetViewTop + offsetScreenTop;
    windowParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
    windowParams.height = WindowManager.LayoutParams.WRAP_CONTENT;

    windowParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE// 不需获取焦点
    | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE// 不需接受触摸事件
    | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON// 保持设备常开,并保持亮度不变。
    | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;// 窗口占满整个屏幕,忽略周围的装饰边框(例如状态栏)。此窗口需考虑到装饰边框的内容。

    // windowParams.format = PixelFormat.TRANSLUCENT;// 默认为不透明,这里设成透明效果.
    windowParams.windowAnimations = 0;// 窗口所使用的动画设置

    ImageView imageView = new ImageView(getContext());
    imageView.setImageBitmap(bm);
    windowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
    windowManager.addView(imageView, windowParams);
    dragImageView = imageView;
    }


    /**
    * 拖动图像在ListView范围内, 不能超过边界
    *
    * @param y
    */
    private void onDrag(int y) {
    int offsetTop = y - offsetViewTop; //顶部不能出界
    int offsetBottom = offsetViewTop + getHeight() - dragImageView.getHeight(); //下边界
    if (dragImageView != null && offsetTop >= 0
    && offsetTop <= getChildAt(getChildCount() - 1).getTop()
    && y <= offsetBottom) {
    windowParams.alpha = 0.8f;// 透明度
    windowParams.y = y - offsetViewTop + offsetScreenTop;// 移动y值.//记得要加上dragOffset,windowManager计算的是整个屏幕.(标题栏和状态栏都要算上)
    windowManager.updateViewLayout(dragImageView, windowParams);// 时时移动.
    }

    onChange(y);

    scrollListView(y);
    }

    /**
    * 同步滑动ListView
    * @param y
    */
    private void scrollListView(int y) {
    View view = getChildAt(dragPosition - getFirstVisiblePosition());
    int offsetY = mLastMotionY - y;

    if (y < getHeight() / 3 && y < mLastMotionY) { //listview向上滑
    setSelectionFromTop(dragPosition, offsetY + view.getTop());
    } else if (y > getHeight() / 3 * 2 && y > mLastMotionY) { //listview向下滑
    setSelectionFromTop(dragPosition, offsetY + view.getTop());
    }
    mLastMotionY = y;
    }


    /**
    * 同步改变item的位置
    * @param y
    */
    private void onChange(int y) {
    int currentPostion = pointToPosition(0, y);

    if (currentPostion == AdapterView.INVALID_POSITION) {
    currentPostion = dragPosition;
    }

    if (dragPosition != currentPostion) {
    DragAdapter adapter = (DragAdapter) getAdapter();
    adapter.change(dragPosition, currentPostion);
    swich(dragPosition, currentPostion);
    }

    dragPosition = currentPostion;
    }

    /***
    * 切换隐藏的位置
    */
    private void swich(int start, int end) {
    getChildAt(start - getFirstVisiblePosition(http://www.amjmh.com)).setVisibility(View.VISIBLE);
    getChildAt(end - getFirstVisiblePosition()).setVisibility(View.INVISIBLE);
    }

    /**
    * 停止拖动,删除影像
    */
    public void stopDrag() {
    if (dragImageView != null) {
    windowManager.removeView(dragImageView);
    dragImageView = null;
    }
    }
    }
    --------------------- 

  • 相关阅读:
    bzoj 1407: [Noi2002]Savage【扩展欧几里得+中国剩余定理】
    bzoj 2142: 礼物【中国剩余定理+组合数学】
    BSGS
    bzoj 2242: [SDOI2011]计算器【扩展欧几里得+快速幂+BSGS】
    bzoj 3122: [Sdoi2013]随机数生成器【BSGS】
    bzoj 3239: Discrete Logging && 2480: Spoj3105 Mod【BSGS】
    bzoj 1180: [CROATIAN2009]OTOCI【LCT】
    51nod 1122 机器人走方格 V4 【矩阵快速幂】
    51nod 1120 机器人走方格 V3 【卡特兰数+卢卡斯定理+组合数】
    51nod 1119 机器人走方格 V2 【组合数学】
  • 原文地址:https://www.cnblogs.com/ly570/p/11284675.html
Copyright © 2011-2022 走看看