Android 拖动组件

Android 拖动组件

@(基本知识)[Android, View, ImageView]

一. 实现方式和场景

  • 主要是有时候需要在页面上,需要悬浮的按钮可以拖动,吸附在屏幕左右2侧;
  • 实现方式有两种方法,如下

    第一种方式:直接自定义组件,自定义ViewonTouch(View v, MotionEvent event)事件,通过View.layout(left,top,right,bottom)更新组件位置;

    第二种方式:悬浮窗模式实现,自定义组件将View添加到Window上面,实现onTouchEvent(MotionEvent event),通过更新View在Window上面的位置来拖动组件(updateViewLayout)。

项目地址 :https://github.com/fenggit/DragView

效果图

二. 实现方式(方式二)

package com.android.main;

import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.widget.ImageView;

/**
 * Author: river
 * Date: 2016/8/23 11:59
 * Description: 拖动组件
 * <p/>
 * getLeft:相对父布局
 * getRawX:相对于屏幕
 * getX:相对于自身View
 */
public class DragView extends ImageView implements View.OnTouchListener {
    private String TAG = DragView.class.getSimpleName();
    /**
     * 记录View与X轴的距离
     */
    private int mLastX;
    /**
     * 记录View与Y轴的距离
     */
    private int mLastY;
    /**
     * 屏幕宽度
     */
    private int mScreenWidth;
    /**
     * 屏幕高度
     */
    private int mScreenHeight;
    /**
     * 状态栏高度
     */
    private final static int STATUS_HEIGHT = 48;
    /**
     * View的距离
     */
    private int left, top, right, bottom;
    /**
     * 是否移动标记
     */
    private boolean isMove = false;

    private int mTouchSlop = 0;

    float mTouchX, mTouchY;

    public DragView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    public DragView(Context context) {
        super(context);
        init(context);
    }

    private void init(Context context) {
        setClickable(true);
        setOnTouchListener(this);

        DisplayMetrics dm = context.getResources().getDisplayMetrics();
        mScreenWidth = dm.widthPixels;
        mScreenHeight = dm.heightPixels - STATUS_HEIGHT;

        mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
        Log.i(TAG, "mTouchSlop=" + mTouchSlop);
//        Log.i(TAG, "w : h " + mScreenWidth + " : " + mScreenHeight);
    }

    int firstX;

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        int action = event.getAction();

        switch (action) {
            case MotionEvent.ACTION_DOWN:
                isMove = false;

                // 相对于屏幕的坐标点
                mLastX = (int) event.getRawX();
                mLastY = (int) event.getRawY();

                // 相对于自身组件的坐标点
                mTouchX = event.getX();
                mTouchY = event.getY();

                break;

            case MotionEvent.ACTION_MOVE:
//                Log.d(TAG, "x  = " + (event.getX() - mTouchX) + "   Y = " + Math.abs(event.getY() - mTouchY));
                // 滑动的最小距离
                if ((Math.abs(event.getX() - mTouchX) > mTouchSlop) || (Math.abs(event.getY() - mTouchY) > mTouchSlop)) {
//                    Log.d(TAG, "move");
                    isMove = true;

                    // 滑动距离
                    int dx = (int) (event.getRawX() - mLastX);
                    int dy = (int) (event.getRawY() - mLastY);

                    left = v.getLeft() + dx;
                    right = v.getRight() + dx;
                    top = v.getTop() + dy;
                    bottom = v.getBottom() + dy;

                    // 下面判断移动是否超出屏幕
                    if (left < 0) {
                        left = 0;
                        right = left + v.getWidth();
                    }

                    if (right > mScreenWidth) {
                        right = mScreenWidth;
                        left = right - v.getWidth();
                    }

                    if (top < 0) {
                        top = 0;
                        bottom = top + v.getHeight();
                    }

                    if (bottom > mScreenHeight) {
                        bottom = mScreenHeight;
                        top = bottom - v.getHeight();
                    }

//                Log.i(TAG, "left= " + left + ";top= " + top + ";right= " + right + ";bottom= " + bottom);

                    v.layout(left, top, right, bottom);

                    mLastX = (int) event.getRawX();
                    mLastY = (int) event.getRawY();

                    return true;
                }

                break;

            case MotionEvent.ACTION_UP:
                if (isMove) {
                    Log.d(TAG, "左右吸附");
                    isMove = false;
                    // 左右吸附
                    if (left > mScreenWidth / 2) {
                        right = mScreenWidth;
                        left = right - v.getWidth();
                    } else {
                        right = v.getWidth();
                        left = 0;
                    }

                    // 上下吸附
//                if (top > mScreenHeight / 2) {
//                    top = mScreenHeight - v.getHeight();
//                    bottom = mScreenHeight;
//                } else {
//                    top = 0;
//                    bottom = v.getHeight();
//                }

                    v.layout(left, top, right, bottom);

                    return true;
                } else {
//                    Log.d(TAG, "click");
                }
                mTouchX = mTouchY = 0;
                break;
        }

        return false;
    }

    /**
     * 获取到状态栏的高度
     *
     * @return
     */
    private int getStatusHeight() {
        Rect frame = new Rect();
        getWindowVisibleDisplayFrame(frame);
        return frame.top;
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值