View基础知识总结

目录

一:View的位置参数

二:获取点击事件发生的x和y坐标

三:TouchSlop

四:VelocityTracker

五:GestureDetector:

六:Scroller:弹性滑动对象,用于实现View的弹性滑动;

七:View的滑动

八:自定义view滑动冲突

九:在Activity中获取宽高


一:View的位置参数

  1. 在Android中有两种坐标系,分别为Android坐标系和View坐标系。

(1)Android坐标系:将屏幕左上角的顶点作为Android坐标系的原点,这个原点向右是X轴正方向,向下是Y轴正方向。

在触控事件中,通过getRawX()和getRawY()方法获得的坐标就是Android坐标系的坐标;

(2)View坐标系:是View到其父控件的坐标;

width=getRight-getLeft;【获取View自身的宽】
height=getBottom-getTop;【获取View自身的高】

通过getTop、getLeft、getBottom、getRight方法可以获得View到其父控件的距离;

 

View基础知识总结_第1张图片

二:获取点击事件发生的x和y坐标

MotoinEvent通过MotionEvent对象,我们可以得到点击事件发生的x和y坐标。

getRawX获取相对屏幕左上角的x坐标,getX相对于当前View左上角的坐标。

通过MotionEvent对象,我们可以获取手指接触屏幕的操作。ACTION_DOWN、ACTION_MOVE、ACTION_UP。

 

三:TouchSlop

TouchSlop是系统认为的滑动最小距离;通俗的说,如果滑动距离小于TouchSlop,系统就不认为这是滑动;

TouchSlop和设备有关,获取代码:

int mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();

四:VelocityTracker

VelocityTracker:速度追踪,用于追踪手指在滑动过程中的速度,包括水平和竖直方向的速度。

手指逆着坐标系的正方向滑动,所产生的速度为负值,顺着正反向滑动,所产生的速度为正值。

4.1:在View的onTouchEvent方法中追踪当前事件的速度:

VelocityTracker   mVelocityTracker = VelocityTracker.obtain();
  mVelocityTracker.addMovement(event);

4.2:当我们想获取当前速度是,采用如下方法:

 mVelocityTracker.computeCurrentVelocity(1000);//设置时间间隔,单位ms
 int velocityY = (int) mVelocityTracker.getYVelocity();
 int velocityX= (int) mVelocityTracker.getXVelocity();

4.3:当我们不需要的时候,需要clear方法重置并回收内存;
mVelocityTracker.clear();
mVelocityTracker.recycle();

五:GestureDetector:

GestureDetector:手势监测,用于辅助检测用户的单击、滑动、长按、双击等行为;

1.创建一个GestureDetector对象,可以实现OnGestureListener或者setOnDoubleTapListener(监听双击行为);


GestureDetector   mGestureDetector = new GestureDetector(new GestureDetector.OnGestureListener() {
});
mGestureDetector.setIsLongpressEnabled(false);//解决长按屏幕后无法拖动的现象;

2.接着在View的onTouchEvent方法中,添加如下实现:

boolean consum = mGestureDetector.onTouchEvent(event);
return  consum;


做完上面两步,我们可以有选择地实现OnGestureListener和OnDoubleTapListener中的方法。

onSingleTapUp(单击)、onFling(快速滑动)、onScroll(拖动)、onLongPress(长按)、onDoubleTap(双击)。

建议:如果只是监听滑动相关的,建议在onTouchEvent中实现。如果要监听双击这种行为,那么就使用OnGestureListener。

 

六:Scroller:弹性滑动对象,用于实现View的弹性滑动;

当使用View的scrollTo/scrollBy方法进行滑动的时候,这个过程是瞬间完成的。这个没有过渡效果的滑动体验很差。

Scroller就可以实现过渡滑动的效果。Scroller本身是不能实现View的滑动的,它需要与View的computeScroll方法结合才能实现弹性滑动的效果。

如何使用Scroller呢?它的典型代码是固定的。

 Scroller scroller = new Scroller(getContext());
    private void smoothScrollTo(int destX, int dextY) {
        int scrollX = getScrollX();
        int delta = destX - scrollX;
        //1000ms滑向dextX
        scroller.startScroll(scrollX,0,delta,0,1000);
        invalidate();
    }
  
   @Override
    public void computeScroll() {
        if (mScroller.computeScrollOffset()) {
            scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
            postInvalidate();
          }
        }

原理:smoothScrollTo方法中调用invalidate方法,invalidate会导致View重绘,调用draw方法。draw方法中调用computeScroll方法,computeScroll是个空实现,需要我们重写。computeScroll会去向scroller获取当前的scrollx和scrolly,调用scrollTo来实现滑动。接着调用postinvalidate进行第二次重绘。如此反复,直到整个滑动过程结束。

七:View的滑动

7.1:View的滑动主要有三种实现方式

1、通过View本身提供的scrollTo/ScrollBy方法,使用scrollTo/ScrollBy来实现View的滑动,只能将View的内容进行移动,并不能将View本身进行移动。

2、通过动画给View施加平移效果来实现滑动,可以实现复杂的动画效果。

3、通过改变View的LayoutParams使得View重新布局从而实现滑动。操作稍微复杂,适用于有交互的View。

比如我们想把一个Button向右平移100px,只需要将这个Button的LayoutParams的marginLeft参数增加100px即可。

ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) mButton.getLayoutParams();

layoutParams.width += 100;

layoutParams.leftMargin += 100;

mButton.requestLayout();

//或者也可以使用  mButton.setLayoutParams(layoutParams);

应用场景:

如果我们实现一个View跟随手滑动的效果:

实现思路:重写onTouchEvent方法,并处理ACTION_MOVE事件。

可以采用改变布局方式的方式实现,也可以使用动画实现(但是因为动画的性质,3.0以下版本无法实现新位置的点击事件)。

 

八:自定义view滑动冲突

1.外部拦截法
     点击事件都先经过父容器的拦截处理,如果父容器需要此事件就拦截。如果不需要就不拦截。这样就可以解决滑动冲突的问题。
     ACTION_DOWN:父容器必须返回false,如果ACTION_DOWN返回true,那么后续的MOVE和UP事件都会直接交由父容器处理。就没办法传递给子View了。
     ACTION_MOVE:根据需要决定是否拦截事件。
     ACTION_UP:这里也必须返回false。如果返回true,就会导致子元素无法获取UP事件。
     怎样判断拦截事件呢?可以根据水平和竖直的滑动距离来判断。

@Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        boolean intercept = false;
        int x = (int) ev.getX();//获取点击事件距离控件左边的距离
        int y = (int) ev.getY();
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                intercept = false;
                break;
            case MotionEvent.ACTION_MOVE:
                if (父容器需要拦截事件) {
                    intercept = true;
                } else {
                    intercept = false;
                }
                break;
            case MotionEvent.ACTION_UP:
                intercept = false;
                break;
            default:
                break;
        }
        mLastXIntercept=x;
        mLastYIntercept=y;
        return intercept;
    }

九:在Activity中获取宽高


有以下三种方法:
view.post、ViewTreeObserver、onWindowFocusChanged
4.1:view.post
Activity获取View的宽高,在onCreate、onResume等方法中获取到的都是0,因为View的测量过程并不是和Activity的生命周期同步执行的。
view.post投递一个Runnable,等looper调用此Runnable的时候,view已经初始化好了。

   view.post(new Runnable() {
            @Override
            public void run() {
                int width = view.getMeasuredWidth();
                int height = view.getMeasuredHeight(); 
            }
        });

4.2:ViewTreeObserver使addOnGlobalLayoutListene
ViewTreeObserver使addOnGlobalLayoutListene
接口, 当view树的状态发生改变或者View树内部的view的可见性发生改变时,onGlobalLayout都会被调用, 需要注意的是,onGlobalLayout方法可能被调用多次, 代码如下:

view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                view.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                int width = view.getMeasuredWidth();
                int height = view.getMeasuredHeight();
            }
        });


4.3:onWindowFocusChanged
onWindowFocusChanged这个方法的含义是View已经初始化完毕了, 宽高已经准备好了, 需要注意的就是这个方法可能会调用多次, 在Activity onResume和onPause的时候都会调用, 也会有多次调用的情况。

 @Override
    public void onWindowFocusChanged(boolean hasWindowFocus) {
        super.onWindowFocusChanged(hasWindowFocus);
        if(hasWindowFocus){
            int width = view.getMeasuredWidth();
            int height = view.getMeasuredHeight();
        }

你可能感兴趣的:(Android)