详细讲解自定义ViewGroup+Scroller+VelocityTracker做出Launcher滑动

来源:互联网 发布:windows的最新版本 编辑:程序博客网 时间:2024/06/03 14:28

转自:http://blog.csdn.net/u014649337/article/details/38302535

滑动在Android UI界面中用的也是比较多的,比如垂直滑动,水平滑动,侧边滑动等等,而且android 也不乏像viewpager这样的滑动控件, 但是有时在做项目的时候,ViewPager

往往不能 满足我们的需求,所以我们需要按照自己的要求自定义滑动组件,比如像自定义ViewGroup 就可以帮助我们实现这个需求,下面我们直接上代码 看看自定ViewGroup

是怎样实现滑动的:


实例代码如下:

自定义ViewGroup ,  MainGroup.java

[java] view plain copy
  1. package com.example.myflaydemo;  
  2.   
  3. import android.content.Context;  
  4. import android.util.AttributeSet;  
  5. import android.util.Log;  
  6. import android.view.MotionEvent;  
  7. import android.view.VelocityTracker;  
  8. import android.view.View;  
  9. import android.view.ViewGroup;  
  10. import android.widget.Scroller;  
  11.   
  12. public class MainGroup extends ViewGroup {  
  13.   
  14.     float mLastionMotionX = 0 ; //记录上次的触摸位置  
  15.     Scroller scroller;  //页面滑动类  
  16.     VelocityTracker velocityTracker; //手势速率跟踪  ,根据触摸位置计算每像素的移动速率  
  17.     int SNAP_VELOCITX = 600//滑动的最小速率  
  18.     int currentScreen = 0;   //第一屏幕  
  19.   
  20.     public MainGroup(Context context, AttributeSet attrs) {  
  21.         super(context, attrs);  
  22.         scroller = new Scroller(context);  
  23.         // TODO Auto-generated constructor stub  
  24.     }  
  25.   
  26.       
  27.     //onLayout 在自定义控件中 作用将决定 子控件的摆放方式(如:水平,垂直)  
  28.     @Override  
  29.     protected void onLayout(boolean changed, int l, int t, int r, int b) {  
  30.         // TODO Auto-generated method stub  
  31.   
  32.         int totalWidth = 0;  
  33.         int childCount = getChildCount();  
  34.         for (int i = 0; i < childCount; i++) {  
  35.             View childView = getChildAt(i);  
  36.             if(childView.getVisibility() != View.GONE){  
  37.                 int childWidth = childView.getMeasuredWidth();  
  38.                 int childHeight = childView.getMeasuredHeight();  
  39.                 childView.layout(totalWidth, 0, totalWidth+childWidth, childHeight);  
  40.                 totalWidth += childWidth;  
  41.             }  
  42.         }  
  43.   
  44.     }  
  45.   
  46.     //onMeasure 作用是用来测量每个子控件的宽高  最后决定自定义控件需要多少空间  
  47.     @Override  
  48.     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
  49.         // TODO Auto-generated method stub  
  50.         super.onMeasure(widthMeasureSpec, heightMeasureSpec);  
  51.         //获取子View的宽高  
  52.         int width = measureWidth(widthMeasureSpec);  
  53.         int height = measureHeight(heightMeasureSpec);  
  54.         //计算ziView尺寸  
  55.         measureChildren(widthMeasureSpec, heightMeasureSpec);  
  56.         //计算自定义View的尺寸  
  57.         setMeasuredDimension(width, height);  
  58.     }  
  59.   
  60.     //计算子View的宽度  
  61.     public int measureWidth(int widthMeasureSpec){  
  62.         int result = 0;  
  63.         int measureMode = MeasureSpec.getMode(widthMeasureSpec);  
  64.         int width = MeasureSpec.getSize(widthMeasureSpec);  
  65.         switch (measureMode) {  
  66.         case MeasureSpec.AT_MOST:  
  67.         case MeasureSpec.EXACTLY:  
  68.             result = width;  
  69.             break;  
  70.         default:  
  71.             break;  
  72.         }  
  73.         return result;  
  74.     }  
  75.   
  76.     //计算子View的高度  
  77.     public int measureHeight(int heightMeasureSpec){  
  78.         int result = 0;  
  79.         int measureMode = MeasureSpec.getMode(heightMeasureSpec);  
  80.         int height = MeasureSpec.getSize(heightMeasureSpec);  
  81.         switch (measureMode) {  
  82.         case MeasureSpec.AT_MOST:  
  83.         case MeasureSpec.EXACTLY:  
  84.             result = height;  
  85.             break;  
  86.         default:  
  87.             break;  
  88.         }  
  89.         return result;  
  90.     }  
  91.   
  92.   
  93.     //onTouchEvent 主要是对 手势操作的处理(如:页面的滑动方向)   
  94.     @Override  
  95.     public boolean onTouchEvent(MotionEvent event) {  
  96.         // TODO Auto-generated method stub  
  97.         float x = event.getX();  
  98.         if(velocityTracker == null){  
  99.             velocityTracker = VelocityTracker.obtain();  
  100.         }  
  101.         //添加触摸对象MotionEvent , 用于计算触摸速率  
  102.         velocityTracker.addMovement(event);  
  103.         //捕获 手势(DOWN,UP,MOVE,CANCEL)  
  104.         int action = event.getAction();  
  105.         switch (action) {  
  106.         case MotionEvent.ACTION_DOWN:  
  107.             mLastionMotionX = x;  
  108.             break;  
  109.         case MotionEvent.ACTION_MOVE:  
  110.             int detalX = (int) (mLastionMotionX-x);  
  111.             //detalX>0 向左滑动  , detalX<0  向右滑动  
  112.             int scrollX = getScrollX();  
  113.             // 边界检查  防止页面滑动超出 显示区域  
  114.             if (detalX < 0 && scrollX + detalX < 0) { //detalX<0 向右滑动,如果不超出左屏幕显示边界 scrollX的绝对值永远是大于detalX滑动的手势距离  
  115.                 detalX = 0 - scrollX; //如果进入此条件,其实只有一种情况,那就是  scrollX = 0  的情况  
  116.             } else if (detalX > 0 && scrollX + detalX > (getChildCount()-1)*getWidth()) {// detalX>0 向左滑动, 如果不超出 右屏幕显示边界,scrollX的绝对值永远是 小于或等于ViewGroup的宽度的  
  117.                 detalX = (getChildCount()-1)*getWidth() - scrollX;//如果进入此条件,也只有一种情况,那就是    scrollX=ViewGroup的宽度  
  118.             }  
  119.             //在原来离远点x坐标 基础上滑动detalX距离  
  120.             scrollBy(detalX, 0);   
  121.             mLastionMotionX = x;  
  122.             break;  
  123.         case MotionEvent.ACTION_UP:  
  124.             int velocityX = (int) velocityTracker.getXVelocity();  
  125.             if(velocityX>SNAP_VELOCITX && currentScreen>0){  
  126.                 snapToScreen(currentScreen-1);  
  127.             }  
  128.             else if(velocityX<-SNAP_VELOCITX && currentScreen<(getChildCount()-1)){  
  129.                 snapToScreen(currentScreen+1);  
  130.             }else{  
  131.                 snapToDestination();  
  132.             }  
  133.             break;  
  134.   
  135.         default:  
  136.             break;  
  137.         }  
  138.   
  139.         return true;  
  140.     }  
  141.   
  142.     @Override  
  143.     public void computeScroll() {  
  144.         // TODO Auto-generated method stub  
  145.         super.computeScroll();  
  146.   
  147.         if(scroller.computeScrollOffset()){  
  148.             scrollTo(scroller.getCurrX(), scroller.getCurrY());  
  149.             postInvalidate();  
  150.         }  
  151.   
  152.     }  
  153.   
  154.     private void snapToDestination() {  
  155.         // TODO Auto-generated method stub  
  156.         //当屏幕滑到getWidth()/2 的时候,此时总共有多少屏,即滑到第几屏  
  157.         int   whichScreen  = ( getScrollX() + getWidth()/2 ) / getWidth();  
  158.         snapToScreen(whichScreen);  
  159.     }  
  160.   
  161.     //加上动画  缓慢的滑动  
  162.     public void snapToScreen(int whichScreen){  
  163.         // 判断 屏幕是否已经滑动到 最后  
  164.         currentScreen = whichScreen;  
  165.         /*if( currentScreen > (getChildCount()-1)){ 
  166.             currentScreen = getChildCount()-1; 
  167.         }*/  
  168.         // 需要滑动的距离    ( 开始 - 剩下 = 需要滑动的距离 )   
  169.         //getScrollX() 滑出屏幕的第一页 开始到 左屏幕边界的距离  
  170.         int dx = currentScreen*getWidth() - getScrollX();  
  171.         //从getScrollX()坐标   滑动dx距离  要花 Math.abs(dx) * 2 ms  
  172.         scroller.startScroll(getScrollX(), 0, dx, 0, Math.abs(dx) * 2);  
  173.         //重新绘制界面  
  174.         postInvalidate();  
  175.     }  
  176.   
  177. }  


ViewGroup在布局文件的使用:

activity_main.xml

[java] view plain copy
  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     xmlns:tools="http://schemas.android.com/tools"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent" >  
  5.   
  6.     <com.example.myflaydemo.MainGroup  
  7.         android:layout_width="match_parent"  
  8.         android:layout_height="match_parent" >  
  9.           
  10.   
  11.         <include layout="@layout/activity_main2" />  
  12.   
  13.         <include layout="@layout/activity_main3" />  
  14.     </com.example.myflaydemo.MainGroup>  
  15.   
  16. </RelativeLayout>  

activity_main2.xml:

[java] view plain copy
  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     xmlns:tools="http://schemas.android.com/tools"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent"  
  5.     >  
  6.   
  7.   <ImageView  
  8.         android:layout_width="fill_parent"  
  9.         android:layout_height="fill_parent"  
  10.         android:background="@drawable/guide03" />      
  11.   
  12. </RelativeLayout>  

activity_main3.xml

[java] view plain copy
  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     xmlns:tools="http://schemas.android.com/tools"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent"  
  5.  >  
  6.   
  7.     <ImageView  
  8.         android:layout_width="fill_parent"  
  9.         android:layout_height="fill_parent"  
  10.         android:background="@drawable/guide04" />  
  11.   
  12. </RelativeLayout>  


注意 guide03和guide04两张图片 你随便在网上找两张图片就可以了.

手势滑动的相关链接:http://blog.csdn.net/shichaosong/article/details/20122513

0 0
原创粉丝点击