目录

一: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到其父控件的距离;

 

二:获取点击事件发生的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();        }

更多相关文章

  1. Android(安卓)4.0.3 联系人(通讯录)应用源码学习
  2. 深入讲解WebView——下
  3. [Android][转]Android(安卓)View绘制13问13答
  4. Android彻底退出应用程序(转)
  5. Android(安卓)Context 是什么?
  6. Android(安卓)studio 注释模板
  7. Android中第五大组件详解
  8. android (三)、Activity工作原理
  9. Android用SharedPreferences记住用户名

随机推荐

  1. Android自定义时间控件不可选择未来时间
  2. Android中线程通讯类Handler
  3. Android(安卓)MediaPlayer与Http Proxy结
  4. android的binder机制研究(C++部分) 分享
  5. Android 开机启动过程
  6. androidの高仿支付宝扫描动画效果
  7. Android Studio Gradle两种更新方式
  8. 关于Android(安卓)O系统短信拦截的流程
  9. android5.0以上对于APP_SWITCH和HOME键的
  10. Android启动模拟器出现:Failed to allocat