Android自定义View实现跟随手指移动

对View的移动,实现的方法有好几种,原理是通过改变View的位置来移动View,下面来实现这样的效果

  • 动画的方法

通过改变View的tranlationX和tranlationY的值来实现移动,首先来写一个自定义View类,重写onTouchEvent方法,实现构造方法

public class MyView extends View {
    public MyView(Context context) {
        super(context);
    }

    public MyView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        return true;//这里我们要消费这个事件,所以返回了true
    }
}

关于移动的处理逻辑都在onTouchEvent方法中,下面的代码主要针对onTouchEvent方法修改,其它代码不再贴上了

首先要获取手指点击移动在屏幕上的坐标,使用

int x = (int)event.getRawX();//获取x轴上的位置 
int y = (int)event.getRawY();//获取y轴上的位置

处理事件的模板代码

switch(event.getAction()){
    case MotionEvent.ACTION_DOWN://点击事件
        break;
    case MotionEvent.ACTION_MOVE://移动事件
        break;
    case MotionEvent.ACTION_UP://离开事件
        break;
    default:
        break;
}

通过判断事件的类型,将在ACTION_MOVE事件中计算移动前后的差值来设置View的translationX和translationY值来改变View的位置,这里需要记录上次的位置,所以需要2个变量,代码如下

private int mLaxtX;
private int mLaxtY;

  @Override
    public boolean onTouchEvent(MotionEvent event) {
        int x = (int) event.getRawX();
        int y = (int) event.getRawY();
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                break;
            case MotionEvent.ACTION_MOVE:
                int deltaX = x - mLastX;//计算x坐标上的差值
                int deltaY = y - mLastY;//计算y坐标上的差值
                float tranX = getTranslationX() + deltaX ;//要平移的x值
                float tranY = getTranslationY() + deltaY;//要平移的y值
                setTranslationX(tranX);//设置值
                setTranslationY(tranY);
                break;
            case MotionEvent.ACTION_UP:

                break;
            default:
                break;
        }
        mLastX = x;//记录上次的坐标
        mLastY = y;
        return true;
    }
  • layout方法

View在绘制的时候,会调用onLayout方法来设置显示的位置,可以通过这个方法来实现移动

//layout方法实现
switch (event.getAction()) {
   case MotionEvent.ACTION_DOWN:
                break;
            case MotionEvent.ACTION_MOVE:
                //计算偏移量
                int offsetX = x - mLastX;
                int offsetY = y - mLastY;
                //重新布局
                layout(getLeft() + offsetX, getTop() + offsetY,
                        getRight() + offsetX, getBottom() + offsetY);
                //也可以使用下面这种方法
//                offsetLeftAndRight(offsetX);
//                offsetTopAndBottom(offsetY);
                break;
            case MotionEvent.ACTION_UP:
                break;
            default:
                break;
        }
        mLastX = x;
        mLastY = y;
  • LayoutParams

LayoutParams保存了一个View的布局参数,通过改变这个参数,重绘View也可以实现移动

//LayoutParams方法
 switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                break;
            case MotionEvent.ACTION_MOVE:
                int offsetX = x - mLastX;
                int offsetY = y - mLastY;
                //示例代码的父View是LinearLayout
                LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) getLayoutParams();
                layoutParams.leftMargin = getLeft() + offsetX;
                layoutParams.topMargin = getTop() + offsetY;
                //下面这两句都可以使用,setLayoutParams也会调用requestLayout
                //                setLayoutParams(layoutParams);
                requestLayout();
                break;
            case MotionEvent.ACTION_UP:
                break;
            default:
                break;
        }

这里先介绍这几种方法

完整代码如下:

public class MyView extends View {
    public MyView(Context context) {
        super(context);
    }

    public MyView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    private int mLastX;
    private int mLastY;

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int x = (int) event.getRawX();
        int y = (int) event.getRawY();
        //动画实现移动代码
        //--------------------------------------------------
//        switch (event.getAction()) {
//            case MotionEvent.ACTION_DOWN:
//
//                break;
//            case MotionEvent.ACTION_MOVE:
//                int delaltax = x - mLastX;
//                int delaltaY = y - mLastY;
//                float tranX = getTranslationX() + delaltax;
//                float tranY = getTranslationY() + delaltaY;
//                setTranslationX(tranX);
//                setTranslationY(tranY);
//                break;
//            case MotionEvent.ACTION_UP:
//
//                break;
//            default:
//                break;
//        }
        //-----------------------------------------------

        //layout方法实现
//        switch (event.getAction()) {
//            case MotionEvent.ACTION_DOWN:
//                break;
//            case MotionEvent.ACTION_MOVE:
//                //计算偏移量
//                int offsetX = x - mLastX;
//                int offsetY = y - mLastY;
//                //重新布局
//                layout(getLeft() + offsetX, getTop() + offsetY,
//                        getRight() + offsetX, getBottom() + offsetY);
//                //也可以使用下面这种方法
                offsetLeftAndRight(offsetX);
                offsetTopAndBottom(offsetY);
//                break;
//            case MotionEvent.ACTION_UP:
//                break;
//            default:
//                break;
//        }
        //---------------------------------------------

        //LayoutParams方法
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                break;
            case MotionEvent.ACTION_MOVE:
                int offsetX = x - mLastX;
                int offsetY = y - mLastY;
                //示例代码的父View是LinearLayout
                LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) getLayoutParams();
                layoutParams.leftMargin = getLeft() + offsetX;
                layoutParams.topMargin = getTop() + offsetY;
                //下面这两句都可以使用,setLayoutParams也会调用requestLayout
                //                setLayoutParams(layoutParams);
                requestLayout();
                break;
            case MotionEvent.ACTION_UP:
                break;
            default:
                break;
        }

        mLastX = x;
        mLastY = y;
        return true;
    }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Android自定义View实现天气预报折线图

    本文实例为大家分享了Android自定义View画天气预报折线图的具体代码,供大家参考,具体内容如下 效果图如下: 刚开始尝试用第三方画曲线的框架来画效果图,后来发现曲线间的阴影当有负数的度数的时候画不出来,而且不需要点击放大.点点可点的效果,用框架显得很臃肿,所以最后用自定义View来画的折线图.自定义画折线图的大致思路:这个图是有多个四边形组成的(4个点连接起来就是一个四边形),两边延伸:添加四个多余的点,将左右的边距设置成负数即可. 代码如下: public class WeatherCh

  • Android自定义View绘制贝塞尔曲线实现流程

    目录 前言 二阶贝塞尔曲线 三阶贝塞尔曲线 前言 对于Android开发,实现贝塞尔曲线还是比较方便的,有对应的API供你调用.由于一阶贝塞尔曲线就是一条直线,实际没啥多大用处,因此,下面主要讲解二阶和三阶. 二阶贝塞尔曲线 在Android中,使用quadTo来实现二阶贝塞尔 path.reset() path.moveTo(startX, startY) path.quadTo(currentX, currentY, endX, endY) canvas.drawPath(path, cur

  • Android自定义view实现侧滑栏详解

    目录 前言 需求 效果图 编写代码 主要问题 前言 上一篇文章学了下自定义View的onDraw函数及自定义属性,做出来的滚动选择控件还算不错,就是逻辑复杂了一些.这篇文章打算利用自定义view的知识,直接手撕一个安卓侧滑栏,涉及到自定义LayoutParams.带padding和margin的measure和layout.利用requestLayout实现动画效果等,有一定难度,但能重新学到很多知识! 需求 这里类似旧版QQ(我特别喜欢之前的侧滑栏),有两层页面,滑动不是最左侧才触发的,而是从

  • Android自定义view实现滚动选择控件详解

    目录 前言 需求 编写代码 主要问题 前言 上篇文章通过一个有header和footer的滚动控件(Viewgroup)学了下MeasureSpec.onMeasure以及onLayout,接下来就用一个滚动选择的控件(View)来学一下onDraw的使用,并且了解下在XML自定义控件参数. 需求 这里就是一个滚动选择文字的控件,还是挺常见的,之前用别人的,现在选择手撕一个,核心思想如下: 1.有三层不同大小及透明度的选项,选中项放在中间 2.接受一个列表的数据,静态时显示三个值,滚动时显示四个

  • Android小工具自定义view课表

    本文实例为大家分享了Android自定义view课表的具体代码,供大家参考,具体内容如下 这里是模拟课表,数据写死了的,不过也可以通过抓包获取教务系统课表 1.xml文件 <?xml version="1.0" encoding="utf-8"?> <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"     xmlns:app="

  • Android自定义View实现水波纹扩散效果

    目录 1.创建RippleView.class, 继承与View 1.1特殊属性解释 1.2新建attrs.xml文件(res/values) 1.3初始化画笔 2.开始绘制onDraw() 效果:水波纹扩散 场景:雷达.按钮点击效果.搜索等 实现:先上效果图,之前记得支付宝有一个咻一咻,当时就是水波纹效果,实现起来一共两步,第一画内圆,第二画多个外圆,不同时创建有间隔创建然后缓慢增大外圆半径,到达最远距离时移除掉,扩散时把透明度从255-1不断赋值即可.复杂在第二步,开工. 开工 1.创建Ri

  • Android自定义View实现时钟功能

    最近在练习自定义view, 想起之前面试的时候笔试有道题是写出自定义一个时钟的关键代码. 今天就来实现一下. 步骤依然是先分析, 再上代码. 实现效果 View分析 时钟主要分为五个部分: 1.中心点: 圆心位置2.圆盘: 以中心点为圆心,drawCircle画个圆3.刻度: paint有个aip, setPathEffect可以根据path画特效, 那么刻度就可以根据圆的path画一个矩形path的特效, 并且这个api只会画特效, 不会画出圆. /** * shape: 特效的path, 这

  • Android自定义View实现跟随手指移动的小兔子

    本文实例为大家分享了Android自定义View实现跟随手指移动的小兔子,供大家参考,具体内容如下 自定义的View实现跟随手指的小兔子 按前面的例子新创建一个project,再在project中新创建一个module 将需要的背景图和兔子图片放入mipmap中 将布局管理器改为帧布局管理器 <?xml version="1.0" encoding="utf-8"?> //修改为帧布局管理器FrameLayout <FrameLayout xmln

  • Android自定义View圆形和拖动圆、跟随手指拖动效果

    单纯的自定义一个圆非常简单 只需要几步就完成 拖动圆添加实现触摸事件即可 我在第一次自定义View圆遇到的几个Bug: 1.拖动圆的话在xml里面设置的自定义圆的宽和高是它能活动的空间的大小 不是圆控件的大小 如果你定义了100dp 拖动它的时候超过100dp这个距离这个圆就会看不见 就像下面这样 如果想活动于整个屏幕直接给宽和高match_parent属性就好了 2.我在定义充满属性match_parent的时候运行会报错,什么方法都用了就是不行,耐心等待过一会就好了-有可能是studio没来

  • Android自定义View圆形和拖动圆跟随手指拖动

    单纯的自定义一个圆非常简单 只需要几步就完成 拖动圆添加实现触摸事件即可 我在第一次自定义View圆遇到的小问题: 1.拖动圆的话在xml里面设置的自定义圆的宽和高是它能活动的空间的大小 不是圆控件的大小 如果你定义了100dp 拖动它的时候超过100dp这个距离这个圆就会看不见 就像下面这样 如果想活动于整个屏幕直接给宽和高match_parent属性就好了 2.在布局里自定的view会提示编译 点击Build编译一下就好了 下面开始写代码: 先是单纯的创建一个圆形 创建一个类继承View 实

  • Android自定义view圆并随手指移动

    本文实例为大家分享了Android自定义view圆并随手指移动的具体代码,供大家参考,具体内容如下 main代码 public class MainActivity extends AppCompatActivity { private int screenW; //屏幕宽度 private int screenH; //屏幕高度 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(saved

  • Android自定义View实现等级滑动条的实例

     Android自定义View实现等级滑动条的实例 实现效果图: 思路: 首先绘制直线,然后等分直线绘制点: 绘制点的时候把X值存到集合中. 然后绘制背景图片,以及图片上的数字. 点击事件down的时候,换小图片为大图片.move的时候跟随手指移动. up的时候根据此时的X计算最近的集合中的点,然后自动吸附回去. 1,自定义属性 <?xml version="1.0" encoding="utf-8"?> <resources> <de

  • Android自定义View实现拖拽效果

    腾讯QQ有那种红点拖动效果,今天就来实现一个简单的自定义View拖动效果,再回到原处,并非完全仿QQ红点拖动. 先来看一下效果图 简单说一下实现步骤 1.创建一个类继承View 2.绘制出一个小球 3.重写onTouchEvent,来根据手指放下,移动,抬起,来控制小球 4.直接在布局中引用 先贴一张图看下View的坐标系 下面就贴一下代码,最后会给出源码 public class CustomView extends View { private int lastX; private int

  • Android自定义View仿探探卡片滑动效果

    Android自定义View仿探探卡片滑动这种效果网上有很多人已经讲解了实现思路,大多都用的是RecyclerView来实现的,但是我们今天来换一种实现思路,只用一个自定义的ViewGroup来搞定这个实现. 下面我们先看一下实现的效果: 这个自定义View用法也很简单,首先从github上下载或者fork这个项目,在布局中添加: <com.liyafeng.view.swipecard.SwipeCardLayout android:id="@+id/scl_layout" a

  • Android自定义View实现拖动自动吸边效果

    本文实例为大家分享了Android自定义View实现拖动自动吸边的具体代码,供大家参考,具体内容如下 自定义View,一是为了满足设计需求,二是开发者进阶的标志之一.随心所欲就是我等奋斗的目标!!! 效果 实现逻辑 明确需求 1.实现控件跟随手指拖动2.实现控件自动贴边 整理思路 1.既然要实现控件拖动,那么就离不开onTouchEvent()这个方法,需要监听里面的按下和滑动事件.2. 要实现自动贴边,需要监听onTouchEvent()中手指离开屏幕事件.对于贴边的过程,我们用属性动画来解决

  • Android自定义View实现折线图效果

    下面就是结果图(每种状态用一个表情图片表示): 一.主页面的布局文件如下: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height=&quo

  • Android自定义View实现开关按钮

    前言:Android自定义View对于刚入门乃至工作几年的程序员来说都是非常恐惧的,但也是Android进阶学习的必经之路,平时项目中经常会有一些苛刻的需求,我们可以在GitHub上找到各种各样的效果,能用则用,不能用自己花功夫改改也能草草了事.不过随着工作经验和工作性质,越来越觉得自定义View是时候有必要自己花点功夫研究一下. 一.经过这两天的努力,自己也尝试着写了一个Demo,效果很简单,就是开关按钮的实现. 可能有的人会说这效果so easy,找UI切三张图就完事了,何必大费周折自定义.

随机推荐