View的基本概念了解

来源:互联网 发布:java上传图片 编辑:程序博客网 时间:2024/05/22 07:58

View方面的东西,乍一眼看去,我真是满脸懵比,雾里看花般难受。

View是所有控件的基类,是一种界面层控件的抽象,代表着一个控件。连ViewGroup都是其子类。而ViewGroup可以直译为控件组,可以包含多个View。
一个View既可以表示一个控件,也可以是多个控件组成的一组控件。

一,View的基础知识

1.1 View的位置参数

一个矩形有四个点,而决定View的位置同样有四个点,分别是left,top,right,bottom。
其中left表示View的左上角距离左边的距离,top表示View的左上角距离上边的距离。
right表示View的右下角距离左边的距离,bottom表示View的右下角距离上边的距离。
当然,这些坐标相对于它的父容器而言的。

View的布局如下:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent">        <asule.myview.ManualView            android:background="#123456"            android:layout_centerInParent="true"            android:layout_width="150dp"            android:layout_height="150dp" /></RelativeLayout>

下面父容器指的是RelativeLayout
这里写图片描述

那么很容易的可以获得View的宽高    int width=right-left;    int height=bootom-top;而得到这个四个位置参数的值,也很简单。    通过View的getLeft,getRight,getTop,getBottom方法。

在android3.0以后,View中又提供了几个位置参数:x,y,transactionX,transactionY四个参数。
x,y表示的是当前View在父容器中左上角的位置,而transactionX和transactionY表示的是View的左上角相对于父容器的偏移量。
所以android3.0以前,左上角的位置就是(left,top),而现在有了偏移量就变为(left+transactionX,top+transactionY)。

x=left+transactionX;y=top+transactionY;

而默认情况下,transactionX和transactionY都为0。如下:

System.out.println("transactionX:" + getTranslationX());System.out.println("transactionY:" + getTranslationY());System.out: transactionX:0.0System.out: transactionY:0.0

1.2 MotionEvent和TouchSlop

MotionEvent处理一些手指在屏幕上产生的事件,如
MotionEvent.ACTION_DOWN,手指按下。
MotionEvent.ACTION_MOVE,手指在屏幕上滑动。
MotionEvent.ACTION_UP,手指松开。

MotionEvent可以监听我们手指产生事件的同时,还可以得到点击事件位置的x和y的坐标。

int x= (int) event.getX();int y= (int) event.getY();int rawX=(int)event.getRawX();int rawY= (int) event.getRawY();getx/getY和getRawX/getRawY有很大的不同。getx/getY得到的是点击事件的位置相对于这个View左上角的x,y坐标。getRawX/getRawY得到的是点击事件的位置相对于手机屏幕左上角的x,y坐标。手机屏幕的x,y为(0,0)

TouchSlop是系统能够识别的可以被滑动的最小距离,如果你滑动的记录小于这个值,那么将不会进行滑动。会认为你滑动距离太短。
它的作用就是,在处理滑动的时候,可以进行对滑动距离的过滤。

得到系统认为的最小滑动距离:int mTouchSlop=ViewConfiguration.get(getContext()).getScaledTouchSlop();

1.3 VelocityTracker,GestureDetector,Scroller

VelocityTracker的例子:

public boolean onTouchEvent(MotionEvent event) {        if (velocityTracker==null){            //创建VelocityTracker对象            velocityTracker = VelocityTracker.obtain();        }        //在onTouchEvent方法中追踪当前MotionEvent事件的速度        velocityTracker.addMovement(event);        //units的单位是毫秒,表示在多少毫秒内来计算的速度。假如你在50毫秒内完成了滑动,那么将计算不出来速度。        velocityTracker.computeCurrentVelocity(100);        /*            computeCurrentVelocity另一个重载方法computeCurrentVelocity(int units, float maxVelocity)            maxVelocity表示最大速率,如果速度大于了maxVelocity,显示的速度为maxVelocity。如果小于的话,那么就显示正常的速度。            velocityTracker.computeCurrentVelocity(1000, (float)20);        */        xVelocity = (int) velocityTracker.getXVelocity();        yVelocity = (int) velocityTracker.getYVelocity();        /*            ACTION_DOWN和ACTION_UP的事件速度一般都为0,真正需要考虑的是ACTION_MOVE时的速度。            怎么计算速度?                速度=(终点位置-起点位置)/规定的毫秒值            本例中规定的毫秒值的是100毫秒。            从左往右滑动,                    滑动的方向和x的正方向相同,那么x方向上的速度就为正值                        如果向下倾斜,与y的正方向相同,那么y方向的速度为正值。            (android中的正方向是水平向右和垂直向下。)        */        switch (event.getAction()){            case MotionEvent.ACTION_DOWN:                System.out.println("ACTION_DOWN");                System.out.println("xVelocity:" + xVelocity);                System.out.println("yVelocity:" + yVelocity);                break;            case MotionEvent.ACTION_MOVE:                System.out.println("ACTION_MOVE");                System.out.println("xVelocity:" + xVelocity);                System.out.println("yVelocity:" + yVelocity);                break;            case MotionEvent.ACTION_UP:                System.out.println("ACTION_UP");                System.out.println("xVelocity:" + xVelocity);                System.out.println("yVelocity:" + yVelocity);                break;        }        return true;    }
//当不需要使用VelocityTracker时重置并回收内存velocityTracker.clear();velocityTracker.recycle();

GestureDetector:

    private MyGestureDetectorListener listener;    private GestureDetector detector;    private void init() {        //创建GestureDetector对象并实现OnGestureListener接口        listener = new MyGestureDetectorListener();        detector = new GestureDetector(listener);    }    /*        轻轻触碰屏幕并抬起                onDown---->onSingleTapUp        长按屏幕后抬起                onDown---->onShowPress---->onLongPress        手指在屏幕上滑动,最后松开                onDown---->onScroll(很多次调用)---->onFling    */    class MyGestureDetectorListener implements GestureDetector.OnGestureListener{        //手指轻轻触碰屏幕触发一瞬间调用        @Override        public boolean onDown(MotionEvent e) {            System.out.println("onDown");            return true;        }        //手指轻轻触碰屏幕,但并没有松开或拖动        @Override        public void onShowPress(MotionEvent e) {            System.out.println("onShowPress");        }        //手指轻轻触碰屏幕,松开。表示单击行为        @Override        public boolean onSingleTapUp(MotionEvent e) {            System.out.println("onSingleTapUp");            return true;        }        //手指在按下并滑动        @Override        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {            System.out.println("onScroll");            return true;        }        //手指长按        @Override        public void onLongPress(MotionEvent e) {            System.out.println("onLongPress");        }        //手指按下屏幕快速滑动后松开        @Override        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {            System.out.println("onFling");            System.out.println("velocityX"+velocityX);            System.out.println("velocityY"+velocityY);            return true;        }    }    @Override    public boolean onTouchEvent(MotionEvent event) {        //接管View的onTouchEvent方法        return detector.onTouchEvent(event);    }

Scroller:

弹性滑动对象,scroolTo和scroolBy两种方法的滑动都是瞬间完成的,没有过渡的滑动效果在。而Scroller可以完成这个过渡效果。它本身无法让View弹性滑动,它需要和View的computeScroll方法配合才能完成这个功能。如何使用Scroller?会在下面介绍scroolTo和scroolBy时通过一个侧滑的demo来使用Scroller。

二,View的滑动

2.1 使用scrollTo和scrollBy
首先看源码:

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();        }    }}public void scrollBy(int x, int y) {    scrollTo(mScrollX + x, mScrollY + y);}可以看出scrollBy实际上也是调用了scrollTo的方法。并且在mScrollX ,mScrollY的基础上进行了移动。scrollBy是绝对移动,它移动时会在上一个的位置上继续移动,而scrollTo却不是,它是直接移动到那个位置。那么mScrollX和mScrollY是什么?public final int getScrollX() {       return mScrollX;}public final int getScrollY() {       return mScrollY;}在view中可以通过getScrollX和getScrollY来获得。mScrollX的值等于View的上边缘在水平方向上的值减去View内容的上边缘在水平方向上的值。同理mScrollY的值等于View的下边缘在竖直方向上的值减去View内容的下边缘在竖直方向上的值。单位是像素。什么是View边缘,什么又是View内容的边缘?View边缘指的是View的位置,由四个顶点组成,而View内容边缘指的是View中内容的边缘。而scrollTo和scrollBy实现滑动,只能将View的内容进行移动。一个概念的了解:android的View视图是没有边界的,也就是说,我们在手机屏幕上看到的,是因为屏幕的限制,我们只能看到这么大。既然这是前提,下面举例子来看。
public class MainActivity extends AppCompatActivity {    private ManualView manual;//自定义的TextView    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        manual = (ManualView) findViewById(R.id.manual);        int scrollX = manual.getScrollX();        int scrollY = manual.getScrollY();        System.out.println("默认情况下"+"ScrollX:"+scrollX + " --- ScrollY:" + scrollY);        findViewById(R.id.btn_scrollby).setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                manual.scrollBy(-20, 0);                int scrollX = manual.getScrollX();                int scrollY = manual.getScrollY();                System.out.println("scrollby移动后" + "ScrollX:" + scrollX + " --- ScrollY:" + scrollY);            }        });        findViewById(R.id.btn_scrollto).setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                manual.scrollTo(100,0);                int scrollX = manual.getScrollX();                int scrollY = manual.getScrollY();                System.out.println("scrollto移动后" + "ScrollX:" + scrollX + " --- ScrollY:" + scrollY);            }        });    }}

运行后:

这里写图片描述

当scrollBy(-20, 0)后,就成为了下面这个样子:

这里写图片描述

前面提到的说每一个View的视图是没有边界的,而只是因为视图的边界超过了它的父容器(可以认为是被隐藏或覆盖),所以只会显示我们眼中看到的布局视图。

这个View没有边界的视图应该是下面这样子:
这里写图片描述

当我们scrollBy(-20,0)时,内容向右移动,滚动时不是以(0,0)作为参照,是调用scrollBy以及scrollTo方法的View自己作为参照。
为什么是向右,要知道View的布局并没有移动,移动的只是View的内容。
View布局的左上减去View内容的左上,此时此刻就是-20。
这里写图片描述
按照上面所说的View边缘和View内容边缘的值的差,可以得出此时的mScrollX为-20。

有时候在想scrollTo和scrollBy移动的只是View的内容,那么有的控件没有内容,又是怎么实现这个方法的呢?

2.2 使用动画完成滑动

使用平移动画或者属性动画。动画以后再深究。

2.3 改变布局参数

通过设置控件的LayoutParams,改变Margin值来达到View的移动。貌似这种方法也想的出来啊。RelativeLayout.LayoutParams params=             (RelativeLayout.LayoutParams) manual.getLayoutParams();params.leftMargin+=100;manual.setLayoutParams(params);//或manual.requestLayout();

2.4 各种滑动方法的对比

scrollTo和scrollBy方法可以很方便的实现滑动功能,但缺点是只能滑动View的内容,不可以滑动View本身。使用动画的话,要注意属性动画只能使用到Android3.0以上,如果要向下兼容,还需要使用第三方的库。改变布局参数,操作有些复杂,适用于有交互的View。
0 0
原创粉丝点击