自定义View是最能体现一个Android开发者水平的技能之一了。

接下来的一些列博客将总结一下Android的自定义相关View知识,包括View的结构,事件体系,工作原理,自定义View的绘制等。

参考资料部分来自于书上以及各种博客。


新建了一个qq群 482543750,欢迎一起学习Android的小伙伴加入。

提供各种Android学习资料,面试资料,Android简历模板。



一、概述Android中,View不属于四大组件,但它甚至比Receiver和Provider都要重要。Android提供了许多基础的控件,但远远不能满足我们的需要,很多时候我们根据需求进行新控件的定义,这就需要我们对View体系有深入理解。
二、基础知识
1、View是什么
View是Android所有控件的基类,简单到TextView、Button,复杂到RelativeLayout,LinearLayout,其共同基类都是View。所以,View可以理解为控件的抽象,也是一个控件。除此之外,还有ViewGroup,字面意义上,它表示控件组,内部可以包含许多个控件。ViewGroup也继承自View,这意味着,一个View的可以是单个控件,也可以是多个控件组成的一组控件,这就形成了View树。下面这个图很好地体现了View的继承关系Android自定义View总结(一)基础知识与实例_第1张图片

2、View的相关参数
View的位置决定于它的四个顶点,对应View的四个属性:Top:左上角纵坐标,通过getTop ()获得Left:左上角横坐标,通过getLeft()获得Right: 右下角横坐标,通过getRight ()获得Bottom: 右下角纵坐标,通过getBottom ()获得
这些坐标都是相对于View的父容器所说的,是一种相对坐标。下面这张图表示的是View中涉及位置参数的各个方法对应的具体含义。最外层是手机屏幕,中间是一个ViewGroup嵌套一个View。涉及到的其他方法请继续往下看。Android自定义View总结(一)基础知识与实例_第2张图片


此外,参数x,y表示View左上角的横纵坐标,translationX和translationY表示View的左上角相对于父容器的偏移量。他们都有相应的Get/Set方法这几个参数也是相对于父容器的坐标可以知道,这几个参数换算关系如下x = left + translationXy = top + translationY
利用这些参数,我们来自定义一个能随手指滑动而改变位置的View实现如下效果:初始位置:Android自定义View总结(一)基础知识与实例_第3张图片

手指滑动后,自定义View走到了图示位置:

Android自定义View总结(一)基础知识与实例_第4张图片

代码如下:自定义View
public class DragView extends View{    int lastX;    int lastY;    public DragView(Context context) {        super(context);    }    public DragView(Context context, AttributeSet attrs) {        super(context, attrs);    }    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);    }    @Override    public boolean onTouchEvent(MotionEvent event) {        int x = (int) event.getX();        int y = (int) event.getY();        Log.e("触发onTouchEvent",x+"::::::"+y);        switch (event.getAction()){            case MotionEvent.ACTION_DOWN:{                lastX = x;                lastY = y;            }            break;            case MotionEvent.ACTION_MOVE:{                int offsetX = x - lastX;                int offsetY = y - lastY;                Log.e("触发ACTION_MOVE",offsetX+"::::::"+offsetY);                layout(getLeft() + offsetX, getTop() + offsetY, getRight() + offsetX, getBottom() + offsetY);                Log.d("DragView",getLeft()+"______"+getTop()+"-------"+getBottom()+"-------"+getRight());            }            break;        }        return true;    }}

布局:

    

MainActivity直接显示布局即可
很好地实现了如上效果

3、MotionEvent和TouchSlop
(1)MotionEvent我们在自定义View的时候,常常需要在onTouchEvent()中定义触摸行为典型的触摸事件类型包括:ACTION_DOWN:手指刚刚接触屏幕ACTION_MOVE:手指在屏幕上移动ACTION_UP:手指从屏幕离开
通过MotionEvent对象,我们可以得到点击事件的一系列位置参数getX(),getY():触摸事件发生的位置相对于View的坐标getRawX(),getRawY()返回返回相对于屏幕左上角的x 和 y 坐标
(2)TouchSlop表示系统能辨识出的认为是滑动的最小距离。若两次滑动小于此常量,判定为不属于滑动操作这个常量的大小和手机有关。
通过如下方式获得:
ViewConfiguration.get(getContext()).getScaledTouchSlop();

我们处理滑动事件时,可以用这个参数进行过滤。
4、VelocityTracker、GestureDetector、Scroller(1)VelocityTracker用于追踪滑动过程中的速度,包括水平和竖直方向的速度。
使用方法:在View的onTouchEvent()中将Event托管给VelocityTracker,采用相应API获取参数
//获取对象VelocityTracker velocityTracker = VelocityTracker.obtain();//托管eventvelocityTracker.addMovement(event);//设置时间间隔,结果会表示为每1000毫秒经过多少像素,若设置为100,结果表示为没100毫秒经过多少像素velocityTracker.computeCurrentVelocity(1000);//获取X和Y方向上的速度int xVelicity = (int) velocityTracker.getXVelocity();int yVelicity = (int) velocityTracker.getYVelocity();
比如1秒内X方向滑动了100像素,那么参数设置为1000时,结果就为100,表示1000毫秒划过100像素参数设置为100时,结果就为10(表示每100毫秒划过10像素)
不需要使用时,对其进行回收
velocityTracker.clear();velocityTracker.recycle();

(2)GestureDetectorGestureDetector中将封装了一系列触摸行为,包括单击、滑动、长按,双击等。使用:
在自定义View中实现onGestureDetector接口,在其中重写onSingleTapTop()-单击事件、onFiling()-快速滑动、omLongPress()-长按、onDoubleTap()-双击等方法,定义自己的事件处理逻辑还有,在onTouchEvent()中:
//获取对象GestureDetector gestureDetector = new GestureDetector(this);//解决长按屏幕后无法拖动的问题gestureDetector.setIsLongpressEnabled(false);//托管eventboolean consume = gestureDetector.onTouchEvent(event);return consume;

(3)Scroller用于实现View的弹性滑动。为了让View实现滑动,我们常常使用scrollTo和ScrollBy,但其过程是瞬间完成的,没有过度效果,用户体验并不好。使用Scroller和View的computeScroll配合,可以实现有过渡效果的滑动


三、View的滑动
滑动是自定义View使用最多的效果之一,有三种实现方式:a、View的scrollTo/ScrollBy方法
b、使用动画为View施加平移效果
c、改变View的LayoutParams是的View重新布局实现滑动
1、使用scrollTo/ScrollBy
源码:
/** * Set the scrolled position of your view. This will cause a call to * {@link #onScrollChanged(int, int, int, int)} and the view will be * invalidated. * @param x the x position to scroll to * @param y the y position to scroll to */public void scrollTo(int x, int y) {    if (mScrollX != x || mScrollY != y) {        int oldX = mScrollX;        int oldY = mScrollY;        mScrollX = x;        mScrollY = y;        invalidateParentCaches();        onScrollChanged(mScrollX, mScrollY, oldX, oldY);        if (!awakenScrollBars()) {            postInvalidateOnAnimation();        }    }}/** * Move the scrolled position of your view. This will cause a call to * {@link #onScrollChanged(int, int, int, int)} and the view will be * invalidated. * @param x the amount of pixels to scroll by horizontally * @param y the amount of pixels to scroll by vertically */public void scrollBy(int x, int y) {    scrollTo(mScrollX + x, mScrollY + y);}

scrollBy实际上也调用scrollTo方法,实现基于当前位置的滑动,scrollTo实现基于所传递参数的绝对滑动mScrollX和mScrollY可以动过get方法得到。mScrollX的值总是等于View的左边缘到View的内容左边缘水平方向的距离,mScrollY的值总是等于View的上边缘和View的内容上边缘竖直方向的距离。
需要注意的是,scrollBy和scrollTo只能改变View的内容的位置而不能改变View在布局中的位置在View的内容位置改变是,mScrollX和mScrollY值可正可负
2、使用动画通过动画可以让一个View进行平移,主要是操作View的translationX和translationY属性,可以用View动画,也可以用属性动画。以属性动画为例,我们在上面例子的基础上添加一个按钮Android自定义View总结(一)基础知识与实例_第5张图片

点击按钮,View在1秒钟的时间内向右平移200像素

Android自定义View总结(一)基础知识与实例_第6张图片

通过如下代码:

Button button = (Button) findViewById(R.id.btn);button.setOnClickListener(new View.OnClickListener() {    @Override    public void onClick(View v) {        dragView.animate().translationX(200).setDuration(1000).start();    }});

3.改变布局参数即改变LayoutParams,比如我们让以上自定义View向右平移100像素只要将此View的marginLeft参数值增加100px
同样以上为例,将自定义View的宽度增加100px,向右平移100px
button.setOnClickListener(new View.OnClickListener() {    @Override    public void onClick(View v) {        RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) dragView.getLayoutParams();        layoutParams.width+=100;        layoutParams.leftMargin+=100;        dragView.requestLayout();        //或者dragView.setLayoutParams(layoutParams);    }});


点击按钮发现View向右滑动而且变胖了,但是瞬间滑动过去的,没有动画效果Android自定义View总结(一)基础知识与实例_第7张图片




更多相关文章

  1. Android L新控件RecyclerView简介
  2. Android其它新控件
  3. Android实现画虚线的控件
  4. Android:控件的对象修改控件的值
  5. Android LayoutInflater.inflate(R.layout.activity_test, conta
  6. android之datepicker控件用法
  7. Android——按钮类控件
  8. Android 控件抖动效果
  9. Android中使用Animation实现控件的动画效果以及Interpolator和An

随机推荐

  1. linux下编译MTK android的环境搭建
  2. android项目迁移到androidX:类映射(android
  3. Android(安卓)Kotlin Activity笔记
  4. android创建文件夹以及向文件写入数据
  5. 内存优化三
  6. 【Android】ViewFlipper的使用
  7. android实现RecyclerView上拉加载,下拉更
  8. andorid底部菜单导航
  9. 1.3 History of Android(安卓)Plug-in Pr
  10. Android(安卓)activity‘s life cycle