自定义控件:(动画)(特效)AllAppList平面矩阵3D效果

 

main.xml

<?xml version="1.0" encoding="utf-8"?>
<com.hhj.appListDemo.ScrollLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@+id/ScrollLayoutTest"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent">
</com.hhj.appListDemo.ScrollLayout>
View Code

app_item.xml 

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="vertical"
  android:gravity="center_horizontal"
  android:layout_width="80dp"
  android:paddingTop="5dp"
  android:layout_height="100dp">
  <ImageView
      android:id="@+id/ivAppIcon"
      android:scaleType="fitCenter"
      android:layout_gravity="center_horizontal|top"
      android:layout_width="48dp"
      android:layout_height="48dp" />
  <TextView
      android:id="@+id/tvAppName"
      android:layout_width="74dp"
      android:ellipsize="marquee"
      android:textColor="#FFFF"
      android:layout_height="50dp"
      android:gravity="center_horizontal|center_vertical" />
</LinearLayout>
View Code

AllAppList.java   (主Activity)

package com.hhj.appListDemo;

import java.util.List;

import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.graphics.Color;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.Window;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.GridView;
import android.widget.Toast;

public class AllAppList extends Activity {
    private static final String TAG = "ScrollLayoutTest";
    private ScrollLayout mScrollLayout;
    private static final float APP_PAGE_SIZE = 16.0f;
    private Context mContext;
    final private int[] color = { Color.BLUE, Color.GRAY, Color.CYAN,
            Color.GREEN, Color.LTGRAY, Color.MAGENTA, Color.RED };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub

        super.onCreate(savedInstanceState);
        this.requestWindowFeature(Window.FEATURE_NO_TITLE);
        mContext = this;
        setContentView(R.layout.main);

        mScrollLayout = (ScrollLayout) findViewById(R.id.ScrollLayoutTest);

        initViews();
    }

    public void initViews() {
        final PackageManager packageManager = getPackageManager();

        final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
        mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);

        // get all apps
        final List<ResolveInfo> apps = packageManager.queryIntentActivities(
                mainIntent, 0);
        System.out.println("apps---->" + apps.size());
        // the total pages
        final int PageCount = (int) Math.ceil(apps.size() / APP_PAGE_SIZE);
        System.out.println("PageCount--->" + PageCount);
        Log.e(TAG, "size:" + apps.size() + " page:" + PageCount);
        for (int i = 0; i < PageCount; i++) {
            GridView appPage = new GridView(this);
            // get the "i" page data
            appPage.setAdapter(new AppAdapter(this, apps, i));
            appPage.setNumColumns(4);
            appPage.setOnItemClickListener(listener);
            // appPage.setBackgroundColor(color[i]);
            mScrollLayout.addView(appPage);
        }
    }

    public OnItemClickListener listener = new OnItemClickListener() {

        public void onItemClick(AdapterView<?> parent, View view, int position,
                long id) {
            // TODO Auto-generated method stub
            ResolveInfo appInfo = (ResolveInfo) parent
                    .getItemAtPosition(position);
            Intent mainIntent = mContext
                    .getPackageManager()
                    .getLaunchIntentForPackage(appInfo.activityInfo.packageName);
            mainIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

            try {
                // launcher the package
                mContext.startActivity(mainIntent);
            } catch (ActivityNotFoundException noFound) {
                Toast.makeText(mContext, "Package not found!",
                        Toast.LENGTH_SHORT).show();
            }
        }

    };

    @Override
    protected void onDestroy() {
        // TODO Auto-generated method stub
        android.os.Process.killProcess(android.os.Process.myPid());
        super.onDestroy();
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        // TODO Auto-generated method stub
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            finish();
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }

}
View Code

AppAdapter.java  (列表适配器)

package com.hhj.appListDemo;

import java.util.ArrayList;
import java.util.List;

import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;

public class AppAdapter extends BaseAdapter {
    private List<ResolveInfo> mList;
    private Context mContext;
    public static final int APP_PAGE_SIZE = 16;
    private PackageManager pm;

    public AppAdapter(Context context, List<ResolveInfo> list, int page) {
        mContext = context;
        pm = context.getPackageManager();

        mList = new ArrayList<ResolveInfo>();
        int i = page * APP_PAGE_SIZE;
        int iEnd = i + APP_PAGE_SIZE;
        while ((i < list.size()) && (i < iEnd)) {
            mList.add(list.get(i));
            i++;
        }
    }

    public int getCount() {
        // TODO Auto-generated method stub
        return mList.size();
    }

    public Object getItem(int position) {
        // TODO Auto-generated method stub
        return mList.get(position);
    }

    public long getItemId(int position) {
        // TODO Auto-generated method stub
        return position;
    }

    public View getView(int position, View convertView, ViewGroup parent) {
        // TODO Auto-generated method stub
        ResolveInfo appInfo = mList.get(position);
        AppItem appItem;
        if (convertView == null) {
            // 初始化 与findViewById类型,只不过findViewById是对控件,而这是对这个布局
            View v = LayoutInflater.from(mContext).inflate(R.layout.app_item,
                    null);

            appItem = new AppItem();
            // 分别用来存储app的图标和名字
            appItem.mAppIcon = (ImageView) v.findViewById(R.id.ivAppIcon);
            appItem.mAppName = (TextView) v.findViewById(R.id.tvAppName);

            v.setTag(appItem);
            convertView = v;
        } else {
            appItem = (AppItem) convertView.getTag();
        }
        // set the icon
        appItem.mAppIcon.setImageDrawable(appInfo.loadIcon(pm));
        // set the app name
        appItem.mAppName.setText(appInfo.loadLabel(pm));

        return convertView;
    }

    public static class AppItem {
        ImageView mAppIcon;
        TextView mAppName;
    }
}
View Code

ScrollLayout.java  (自定义动画控件)

package com.hhj.appListDemo;

import java.util.Random;

import com.hhj.appListDemo.AppAdapter.AppItem;

import android.content.Context;
import android.content.pm.ResolveInfo;
import android.graphics.Bitmap;
import android.graphics.Camera;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PaintFlagsDrawFilter;
import android.graphics.drawable.BitmapDrawable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.animation.Transformation;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.ListAdapter;
import android.widget.Scroller;

public class ScrollLayout extends ViewGroup {

    private boolean type;
    
    /** 沿Y轴正方向看,数值减1时动画逆时针旋转。 */
    public static final boolean ROTATE_DECREASE = true;
    /** 沿Y轴正方向看,数值减1时动画顺时针旋转。 */
    public static final boolean ROTATE_INCREASE = false;
    
    /** 值为true时可明确查看动画的旋转方向。 */
    public static final boolean DEBUG = false;
    
    private static final String TAG = "ScrollLayout";
    // 用于滑动的类
    private Scroller mScroller;
    // 用来跟踪触摸速度的类
    private VelocityTracker mVelocityTracker;
    // 当前的屏幕视图
    private int mCurScreen;
    // 默认的显示视图
    private int mDefaultScreen = 0;
    // 无事件的状态
    private static final int TOUCH_STATE_REST = 0;
    // 处于拖动的状态
    private static final int TOUCH_STATE_SCROLLING = 1;
    // 滑动的速度
    private static final int SNAP_VELOCITY = 600;

    private static int mNum;
    
    private int mTouchState = TOUCH_STATE_REST;
    private int mTouchSlop;
    private float mLastMotionX;
    // 用来处理立体效果的类
    private Camera mCamera;
    private Matrix mMatrix;
    /**旋转的角度*/
    private float angle = 180;

    public ScrollLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
        // TODO Auto-generated constructor stub
    }

    // 在构造器中初始化
    public ScrollLayout(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        // TODO Auto-generated constructor stub
        mScroller = new Scroller(context);

        mCurScreen = mDefaultScreen;
        mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();

        mCamera = new Camera();
        mMatrix = new Matrix();
    }

    /*
     * 
     * 为子View指定位置
     */
    protected void onLayout(boolean changed, int left, int top, int right,
            int bottom) {
        // TODO Auto-generated method stub
        Log.e(TAG, "onLayout");

        if (changed) {
            int childLeft = 0;
            final int childCount = getChildCount();

            for (int i = 0; i < childCount; i++) {
                final View childView = getChildAt(i);
                if (childView.getVisibility() != View.GONE) {
                    final int childWidth = childView.getMeasuredWidth();
                    childView.layout(childLeft, 0, childLeft + childWidth,
                            childView.getMeasuredHeight());
                    childLeft += childWidth;
                }
            }
        }
    }

    // 重写此方法用来计算高度和宽度
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        Log.e(TAG, "onMeasure");
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        final int width = MeasureSpec.getSize(widthMeasureSpec);
        final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        // Exactly:width代表的是精确的尺寸
        // AT_MOST:width代表的是最大可获得的空间
        if (widthMode != MeasureSpec.EXACTLY) {
            throw new IllegalStateException(
                    "ScrollLayout only canmCurScreen run at EXACTLY mode!");
        }

        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        if (heightMode != MeasureSpec.EXACTLY) {
            throw new IllegalStateException(
                    "ScrollLayout only can run at EXACTLY mode!");
        }

        // The children are given the same width and height as the scrollLayout
        // 得到多少页(子View)并设置他们的宽和高
        final int count = getChildCount();
        for (int i = 0; i < count; i++) {
            getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec);
        }
        // Log.e(TAG, "moving to screen "+mCurScreen);
        scrollTo(mCurScreen * width, 0);
    }
    
    
    
    /**
     * 当进行View滑动时,会导致当前的View无效,该函数的作用是对View进行重新绘制 调用drawScreen函数
     */
    protected void dispatchDraw(Canvas canvas) {
        // TODO Auto-generated method stub
        final long drawingTime = getDrawingTime();
        final int count = getChildCount();
        //Log.i("HHJ", "125"+"   drawingTime:"+drawingTime+"           count:"+count);
        for (int i = 0; i < count; i++) {
            drawScreenCube(canvas, i, drawingTime,mNum);//mNum
        }
    }
    
    class BigStone {
        //图片
        Bitmap bitmap;
        //角度
        int angle;
        //x坐标
        float x;
        //y坐标
        float y;
        //是否可见
        String text;
        boolean isVisible = true;
    }
    
    /**
     * 计算每个点的坐标
     */
    private void computeCoordinates() {
        BigStone stone;
        for(int index=0; index<STONE_COUNT; index++) {
            stone = mStones[index];
            stone.x = mPointX+ (float)(mRadius * Math.cos(stone.angle*Math.PI/90));//stone.angle*Math.PI/180(弧度=角度*3.14)
            stone.y = mPointY+ (float)(mRadius * Math.sin(stone.angle*Math.PI/90));
        }
    }
    //stone列表
    private BigStone[] mStones;
    //数目
    private int STONE_COUNT ;
    
    /**圆心坐标*/
    private int mPointX=0, mPointY=0;
    /**半径*/
    private int mRadius = 120;
    /**每两个点间隔的角度*/
    private int mDegreeDelta;
    private Context context;
    
    private Paint mPaint = new Paint();
/*    
    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        if(event.getAction() == MotionEvent.ACTION_DOWN){
            firstDegree =mStones[0].angle;
        }
        return true;
    }*/
    /**
     * 立体效果的实现函数 ,screen为哪一个子View  立方体效果
     * 
     */
    public void drawScreenCube(Canvas canvas, int screen, long drawingTime ,int select) {
        canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG|Paint.FILTER_BITMAP_FLAG));
        
        if(select==1){//圆圈

           super.dispatchDraw(canvas);
        }else if(select==2){//层叠透明变亮
            final int width = getWidth(); 
            final int scrollWidth = screen * width; 
            final int scrollX = this.getScrollX();  
            if(scrollWidth > scrollX + width || scrollWidth + width < scrollX) { 
                return; 
            } 
            final View child;// = getChildAt(screen); 
            
            float scaleX = 1f;/*设置矩阵大小*/
            float scaleY = 1f;
            
            float centerX= (scrollWidth < scrollX)?scrollWidth + width:scrollWidth; //中心位置
            float centerY=getHeight()/2;
            
            if(screen==mCurScreen+1 && getChildAt(mCurScreen+1)!=null){
                child = getChildAt(mCurScreen+1);
                Log.i("HHJ", "child:"+child.toString());
                scaleX = (float) (((getScrollX()-(mCurScreen*getMeasuredWidth()))) * (1.0 / getMeasuredWidth()));
                scaleY = scaleX;
                centerX = (scrollWidth < scrollX)?scrollWidth + width:scrollWidth-getMeasuredWidth()/2; 
                centerY = getHeight()/2; 
            }else if(screen==mCurScreen-1 && getChildAt(mCurScreen-1)!=null){
                child = getChildAt(mCurScreen-1);
            }else {
                child = getChildAt(mCurScreen);
                if(scrollX<mCurScreen*getMeasuredWidth()){
                    scaleX = (float) (Math.abs(getScrollX()-mCurScreen*getMeasuredWidth()) * (1.0 / getMeasuredWidth())-1);
                    scaleY = scaleX;
                    centerX = (scrollWidth < scrollX)?scrollWidth + width:scrollWidth-getMeasuredWidth()/2; 
                    centerY = getHeight()/2; 
                }
            }
            
            final Camera camera = mCamera; 
            final Matrix matrix = mMatrix; 
            canvas.save(); 
            camera.save(); 
            camera.rotateY(-0);
            
            camera.getMatrix(matrix); 
            camera.restore(); 
            
            matrix.preScale(Math.abs(scaleX),Math.abs(scaleY));//大小
            //matrix.postScale(scaleX, scaleY);
            
            matrix.preTranslate(-centerX, -centerY); //中心位置
            matrix.postTranslate(centerX, centerY); 
            
            canvas.concat(matrix);
            drawChild(canvas, child, drawingTime); 
            canvas.restore(); 
        }else if(select==3){//波浪情况
            final int width = getWidth(); 
            final int scrollWidth = screen * width; 
            final int scrollX = this.getScrollX();  
            if(scrollWidth > scrollX + width || scrollWidth + width < scrollX) { 
                return; 
            } 
            final View child;// = getChildAt(screen); 
            float scaleX = 1f;
            float scaleY = 1f;
            if(screen==mCurScreen+1 && getChildAt(mCurScreen+1)!=null){
                child = getChildAt(mCurScreen+1);
                scaleX = (float) ((float) ((getScrollX()-(mCurScreen*getMeasuredWidth()))) * (1.0 / getMeasuredWidth()));
                scaleY = scaleX;
            }else if(screen==mCurScreen-1 && getChildAt(mCurScreen-1)!=null){
                child = getChildAt(mCurScreen-1);
                scaleX = (float) ((float) ((getScrollX()-(mCurScreen*getMeasuredWidth()))) * (1.0 / getMeasuredWidth()));
                scaleY = scaleX;
            }else {
                child = getChildAt(mCurScreen);
            }
            
            final float centerX = (scrollWidth < scrollX)?scrollWidth + width:scrollWidth; 
            final float centerY = getHeight()/2; 
            
            
            final Camera camera = mCamera; 
            final Matrix matrix = mMatrix; 
            canvas.save(); 
            camera.save(); 
            camera.rotateY(-0);
            
            camera.getMatrix(matrix); 
            camera.restore(); 
            
            matrix.preScale(Math.abs(scaleX), Math.abs(scaleY));
            //matrix.postScale(scaleX, scaleY);
            
            matrix.preTranslate(-centerX, -centerY); 
            matrix.postTranslate(centerX, centerY); 
            
            canvas.concat(matrix); 
            drawChild(canvas, child, drawingTime); 
            canvas.restore(); 
        }else if(select==4){//立体翻转
            final int width = getWidth(); 
            final int scrollWidth = screen * width; 
            final int scrollX = this.getScrollX();  
            if(scrollWidth > scrollX + width || scrollWidth + width < scrollX) { 
                return; 
            } 
            final View child = getChildAt(screen); 
            final int faceIndex = screen; 
            final float faceDegree = (this.getScrollX() - faceIndex *480f)*0.1875f;
            final float currentDegree = getScrollX() * (angle / getMeasuredWidth());
            if(faceDegree > 90 || faceDegree < -90) { 
                return; 
            }         
            final float centerX = (scrollWidth < scrollX)?scrollWidth + width:scrollWidth; 
            final float centerY = getHeight()/2; 
            final Camera camera = mCamera; 
            final Matrix matrix = mMatrix; 
            canvas.save(); 
            camera.save(); 
            camera.rotateY(-faceDegree); 
            camera.getMatrix(matrix); 
            camera.restore(); 
            matrix.preTranslate(-centerX, -centerY); 
            matrix.postTranslate(centerX, centerY); 
            canvas.concat(matrix); 
            drawChild(canvas, child, drawingTime); 
            canvas.restore(); 
        }else if (select==5){
            // 得到当前子View的宽度
            final int width = getWidth();
            
            /**当前滑动到view视图在viewgroup里面到位置   scrollWidth = 屏数*该view到宽度  */
            final int scrollWidth = screen * width;
            /**View水平方向的偏移量(像素)*/
            final int scrollX = this.getScrollX();
            if (scrollWidth > scrollX + width || scrollWidth + width < scrollX) {
                return;
            }
            final View child = getChildAt(screen);
            final int faceIndex = screen;
            
            /**
             * 1.解锁下这里到意思  由于当前一屏所充满屏幕宽度(假如所480*800)480    
           * 2. 180/getMeasuredWidth() 当前屏总共分为180度  比上 当前屏总宽度 意思说屏每一个像素到滑动占多少角度    意思所说180/480=0.375 每移动一个像素就所要转动0.375个角度 
           * 3. getScrollX() 由于这个所一个viewgroup 上滑动到偏移量 ,所有等有所将viewgroup翻转了很多个180
             *    等于说所第一屏所0~180度   第二屏所 180 ~ 360 度   第三屏所 360~540度 依次将viewgroup翻转到角度而已
             *  */
            final float currentDegree = getScrollX() * (angle / getMeasuredWidth());
            /**
             * 1.当前翻转到角度   currentDegree-当前屏数*180
             * 2.这里这样一减当前到滑屏度数就控制在-180~0度之间了
             * 3.让后在加上下面一个if判断,是将当前一屏与屏成九十度到时候以后的滑动就注销掉老
             * 
             **/
            final float faceDegree = currentDegree - faceIndex * angle;
            if (faceDegree > 90 || faceDegree < -90) {
                return;
            }
            
            //旋转的x轴中心位置
            final float centerX = (scrollWidth < scrollX) ? scrollWidth + width: scrollWidth;
            Log.i("HHJ", "centerX:"+centerX+"    scrollWidth:"+scrollWidth+"   scrollX:"+scrollX);
            //旋转的y轴中心位置
            final float centerY = getHeight() / 2;
            final Camera camera = mCamera;
            final Matrix matrixX = mMatrix;
            canvas.save();
            camera.save();
            camera.rotateY(-faceDegree);
            camera.getMatrix(matrixX);
            camera.restore();
            matrixX.preTranslate(-centerX, -centerY);//特效处理的中心
            matrixX.postTranslate(centerX, centerY);
            canvas.concat(matrixX);
            drawChild(canvas, child, drawingTime);
            canvas.restore();
        }else {
            super.dispatchDraw(canvas);
        }

    }
    
    /**
     * 把中心点放到中心处
     * @param canvas
     * @param bitmap
     * @param left
     * @param top
     */
    void drawInCenter(Canvas canvas, Bitmap bitmap, float left, float top,String text) {
        canvas.drawPoint(left, top, mPaint);
        Log.i("HHJ","bitmap==null:"+(bitmap==null));
        canvas.drawBitmap(bitmap, left-bitmap.getWidth()/2, top-bitmap.getHeight()/2, null);
        canvas.drawText(text,left-bitmap.getWidth()/2+2, top+bitmap.getHeight()/2+8, mPaint);
        canvas.restore(); 
    }

    /**
     * 根据目前的位置滚动到下一个视图位置.
     */
    public void snapToDestination() {
        final int screenWidth = getWidth();
        // 根据View的宽度以及滑动的值来判断是哪个View
        final int destScreen = (getScrollX() + screenWidth / 2) / screenWidth;
        snapToScreen(destScreen);
    }

    public void snapToScreen(int whichScreen) {
        // get the valid layout page
        whichScreen = Math.max(0, Math.min(whichScreen, getChildCount() - 1));
        if (getScrollX() != (whichScreen * getWidth())) {

            final int delta = whichScreen * getWidth() - getScrollX();
            mScroller.startScroll(getScrollX(), 0, delta, 0,
                    Math.abs(delta) * 2);
            mCurScreen = whichScreen;
            invalidate(); // 重新布局
        }
    }

    public void setToScreen(int whichScreen) {
        whichScreen = Math.max(0, Math.min(whichScreen, getChildCount() - 1));
        mCurScreen = whichScreen;
        scrollTo(whichScreen * getWidth(), 0);
    }

    public int getCurScreen() {
        return mCurScreen;
    }

    @Override
    public void computeScroll() {
        // TODO Auto-generated method stub
        if (mScroller.computeScrollOffset()) {
            //Log.i("HHJ", "209"+mScroller.computeScrollOffset());
            scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
            postInvalidate();
        }
    }

    
    
    public boolean onTouchEvent(MotionEvent event) {
        // TODO Auto-generated method stub

        if (mVelocityTracker == null) {
            // 使用obtain方法得到VelocityTracker的一个对象
            mVelocityTracker = VelocityTracker.obtain();
        }
        // 将当前的触摸事件传递给VelocityTracker对象
        mVelocityTracker.addMovement(event);
        // 得到触摸事件的类型
        final int action = event.getAction();
        final float x = event.getX();

        switch (action) {
        case MotionEvent.ACTION_DOWN:
            Log.e(TAG, "event down!");
            if (!mScroller.isFinished()) {
                mScroller.abortAnimation();
            }
            mLastMotionX = x;
            break;

        case MotionEvent.ACTION_MOVE:
            int deltaX = (int) (mLastMotionX - x);
            mLastMotionX = x;

            scrollBy(deltaX, 0);
            break;

        case MotionEvent.ACTION_UP:
            Log.e(TAG, "event : up");
            // if (mTouchState == TOUCH_STATE_SCROLLING) {
            final VelocityTracker velocityTracker = mVelocityTracker;
            // 计算当前的速度
            velocityTracker.computeCurrentVelocity(1000);
            // 获得当前的速度
            int velocityX = (int) velocityTracker.getXVelocity();

            if (velocityX > SNAP_VELOCITY && mCurScreen > 0) {
                // Fling enough to move left
                snapToScreen(mCurScreen - 1);
            } else if (velocityX < -SNAP_VELOCITY && mCurScreen < getChildCount() - 1) {
                // Fling enough to move right
                snapToScreen(mCurScreen + 1);
            } else {
                snapToDestination();
            }

            if (mVelocityTracker != null) {
                mVelocityTracker.recycle();
                mVelocityTracker = null;
            }
            // }
            mTouchState = TOUCH_STATE_REST;
            break;
        case MotionEvent.ACTION_CANCEL:
            mTouchState = TOUCH_STATE_REST;
            break;
        }

        return true;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        // TODO Auto-generated method stub
        Log.e(TAG, "onInterceptTouchEvent-slop:" + mTouchSlop);

        final int action = ev.getAction();
        if ((action == MotionEvent.ACTION_MOVE)
                && (mTouchState != TOUCH_STATE_REST)) {
            return true;
        }

        final float x = ev.getX();

        switch (action) {
        case MotionEvent.ACTION_MOVE:
            final int xDiff = (int) Math.abs(mLastMotionX - x);
            if (xDiff > mTouchSlop) {
                mTouchState = TOUCH_STATE_SCROLLING;

            }
            break;

        case MotionEvent.ACTION_DOWN:
            
            mNum = new Random().nextInt(10);
            mLastMotionX = x;
            mTouchState = mScroller.isFinished() ? TOUCH_STATE_REST
                    : TOUCH_STATE_SCROLLING;
            break;

        case MotionEvent.ACTION_CANCEL:
        case MotionEvent.ACTION_UP:
            mTouchState = TOUCH_STATE_REST;
            break;
        }

        return mTouchState != TOUCH_STATE_REST;
    }


}
View Code

 

 DEMO完整路径下载:http://download.csdn.net/detail/androidsj/5537231

 

 【滑动的时候九宫格图标变成原形】

 

package com.hhj.allApp;

import java.util.Random;
import com.hhj.allApp.AppAdapter.AppItem;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Camera;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.drawable.BitmapDrawable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.widget.GridView;
import android.widget.Scroller;

public class ScrollLayout extends ViewGroup {

    private static final String TAG = "HHJ";
    // 用于滑动的类
    private Scroller mScroller;
    // 用来跟踪触摸速度的类
    private VelocityTracker mVelocityTracker;
    // 当前的屏幕视图
    private int mCurScreen;
    // 默认的显示视图
    private int mDefaultScreen = 0;
    // 无事件的状态
    private static final int TOUCH_STATE_REST = 0;
    // 处于拖动的状态
    private static final int TOUCH_STATE_SCROLLING = 1;
    // 滑动的速度
    private static final int SNAP_VELOCITY = 600;

    private int mTouchState = TOUCH_STATE_REST;
    private int mTouchSlop;
    private float mLastMotionX;
    // 用来处理立体效果的类
    private Camera mCamera;
    private Matrix mMatrix;
    // 旋转的角度
    private float angle = 100;
    
    private int mNum;
    
    Paint mPaint = new Paint();
    
    private Context mContext;

    public ScrollLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
        mContext = context;
        // TODO Auto-generated constructor stub
    }

    // 在构造器中初始化
    public ScrollLayout(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        // TODO Auto-generated constructor stub
        mScroller = new Scroller(context);

        mCurScreen = mDefaultScreen;
        mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();

        mCamera = new Camera();
        mMatrix = new Matrix();
    }

    /*
     * 
     * 为子View指定位置
     */
    protected void onLayout(boolean changed, int left, int top, int right,
            int bottom) {
        // TODO Auto-generated method stub
        Log.e(TAG, "onLayout");

        if (changed) {
            int childLeft = 0;
            final int childCount = getChildCount();

            for (int i = 0; i < childCount; i++) {
                final View childView = getChildAt(i);
                if (childView.getVisibility() != View.GONE) {
                    final int childWidth = childView.getMeasuredWidth();
                    childView.layout(childLeft, 0, childLeft + childWidth,
                            childView.getMeasuredHeight());
                    childLeft += childWidth;
                }
            }
        }
    }

    // 重写此方法用来计算高度和宽度
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        Log.e(TAG, "onMeasure");
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        final int width = MeasureSpec.getSize(widthMeasureSpec);
        final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        // Exactly:width代表的是精确的尺寸
        // AT_MOST:width代表的是最大可获得的空间
        if (widthMode != MeasureSpec.EXACTLY) {
            throw new IllegalStateException(
                    "ScrollLayout only canmCurScreen run at EXACTLY mode!");
        }

        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        if (heightMode != MeasureSpec.EXACTLY) {
            throw new IllegalStateException(
                    "ScrollLayout only can run at EXACTLY mode!");
        }

        // The children are given the same width and height as the scrollLayout
        // 得到多少页(子View)并设置他们的宽和高
        final int count = getChildCount();
        for (int i = 0; i < count; i++) {
            getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec);
        }
        // Log.e(TAG, "moving to screen "+mCurScreen);
        scrollTo(mCurScreen * width, 0);
    }

    /*
     * 当进行View滑动时,会导致当前的View无效,该函数的作用是对View进行重新绘制 调用drawScreen函数
     */
    protected void dispatchDraw(Canvas canvas) {
        //Log.i(TAG, "dispatchDraw");
        final long drawingTime = getDrawingTime();
        final int count = getChildCount();
        for (int i = 0; i < count; i++) {
            drawScreen(canvas, i, drawingTime,1);//mNum
        }
    }
    BigStone[] mStones;
    /**圆心坐标*/
    int mPointX=0, mPointY=0;
   /**定义一个圆的半径*/
    int mRadius = 180;
    
    /**定义一个陀螺的半径*/
    int[] mmRadius = {30,40,50,60,70,80,90,100,110,120,130,140,150,160,170,180};
    /**每两个点间隔的角度*/
    int mDegreeDelta;
    /**是否在拖动*/
    boolean isDrag=false;

    public void drawScreen(Canvas canvas, int screen, long drawingTime,int selsect) {
        if(selsect == 1){ //
            Log.i(TAG, "isDrag:"+isDrag+"    "+getScrollX());
            if(isDrag){
                GridView gridView = (GridView) getChildAt(screen);
                int width = getWidth();
                int height = getHeight();
                int screenCount = gridView.getChildCount();
                mStones = new BigStone[screenCount];;
                
                mPointX = screen*width+width/2;
                mPointY =height/2;
                
                BigStone stone;
                int angle = 0;
                mDegreeDelta = 180/screenCount;
                
                for(int index=0; index<screenCount; index++) {
                    stone = new BigStone();
                    stone.angle = angle;  
                    AppItem info = (AppItem) gridView.getChildAt(index).getTag();//将得到的icon图片赋值给图标
                    BitmapDrawable bd = (BitmapDrawable)info.mAppIcon.getDrawable();     
                    stone.text = "" +info.mAppName.getText().toString();
                    stone.bitmap  = bd.getBitmap();
                    angle += mDegreeDelta;
                    mStones[index] = stone;
                }
                
                BigStone stoneInit;
                for(int index=0; index<screenCount; index++) {
                    stoneInit = mStones[index];
                    stoneInit.x = mPointX+ (float)(mRadius * Math.cos(stoneInit.angle*Math.PI/90));//stone.angle*Math.PI/180(弧度=角度*3.14)
                    stoneInit.y = mPointY+ (float)(mRadius * Math.sin(stoneInit.angle*Math.PI/90));
                }
                
                
                for(int index=0; index<screenCount; index++) {
                    canvas.drawPoint(mStones[index].x, mStones[index].y, mPaint);
                    canvas.drawBitmap(mStones[index].bitmap, mStones[index].x-mStones[index].bitmap.getWidth()/2, mStones[index].y-mStones[index].bitmap.getHeight()/2, null);
                    canvas.drawText(mStones[index].text,mStones[index].x-mStones[index].bitmap.getWidth()/2+2, mStones[index].y+mStones[index].bitmap.getHeight()/2+8, mPaint);
                }
            }else{
                super.dispatchDraw(canvas);
            }

            

        } else if(selsect==2){
            // 得到当前子View的宽度
            final int width = getWidth();
            final int scrollWidth = screen * width;
            final int scrollX = this.getScrollX();
            if (scrollWidth > scrollX + width || scrollWidth + width < scrollX) {
                return;
            }
            final View child = getChildAt(screen);
            final int faceIndex = screen;
            final float currentDegree = getScrollX() * (angle / getMeasuredWidth());
            final float faceDegree = currentDegree - faceIndex * angle;
            if (faceDegree > 90 || faceDegree < -90) {
                return;
            }
            final float centerX = (scrollWidth < scrollX) ? scrollWidth + width
                    : scrollWidth;
            final float centerY = getHeight() / 2;
            final Camera camera = mCamera;
            final Matrix matrix = mMatrix;
            canvas.save();
            camera.save();
            camera.rotateY(-faceDegree);
            camera.getMatrix(matrix);
            camera.restore();
            matrix.preTranslate(-centerX, -centerY);
            matrix.postTranslate(centerX, centerY);
            canvas.concat(matrix);
            drawChild(canvas, child, drawingTime);
            canvas.restore();
        }

    }
    
    /**
     * 根据目前的位置滚动到下一个视图位置.
     */
    public void snapToDestination() {
        final int screenWidth = getWidth();
        // 根据View的宽度以及滑动的值来判断是哪个View
        final int destScreen = (getScrollX() + screenWidth / 2) / screenWidth;
        snapToScreen(destScreen);
    }

    public void snapToScreen(int whichScreen) {
        // get the valid layout page
        whichScreen = Math.max(0, Math.min(whichScreen, getChildCount() - 1));
        if (getScrollX() != (whichScreen * getWidth())) {

            final int delta = whichScreen * getWidth() - getScrollX();
            mScroller.startScroll(getScrollX(), 0, delta, 0,
                    Math.abs(delta) * 2);
            mCurScreen = whichScreen;
            invalidate(); // 重新布局
        }
    }

    public void setToScreen(int whichScreen) {
        whichScreen = Math.max(0, Math.min(whichScreen, getChildCount() - 1));
        mCurScreen = whichScreen;
        scrollTo(whichScreen * getWidth(), 0);
    }

    public int getCurScreen() {
        return mCurScreen;
    }

    @Override
    public void computeScroll() {
        // TODO Auto-generated method stub
        if (mScroller.computeScrollOffset()) {
            scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
            postInvalidate();
        }
    }

    public boolean onTouchEvent(MotionEvent event) {
        // TODO Auto-generated method stub
        //Log.i(TAG, "onTouchEvent");
        
        if (mVelocityTracker == null) {
            // 使用obtain方法得到VelocityTracker的一个对象
            mVelocityTracker = VelocityTracker.obtain();
        }
        // 将当前的触摸事件传递给VelocityTracker对象
        mVelocityTracker.addMovement(event);
        // 得到触摸事件的类型
        final int action = event.getAction();
        final float x = event.getX();

        switch (action) {
        case MotionEvent.ACTION_DOWN:
            
            if (!mScroller.isFinished()) {
                mScroller.abortAnimation();
            }
            mLastMotionX = x;
            break;

        case MotionEvent.ACTION_MOVE:
            isDrag = true;
            int deltaX = (int) (mLastMotionX - x);
            mLastMotionX = x;

            scrollBy(deltaX, 0);
            break;

        case MotionEvent.ACTION_UP:
            isDrag = false;
            //Log.e(TAG, "event : up");
            // if (mTouchState == TOUCH_STATE_SCROLLING) {
            final VelocityTracker velocityTracker = mVelocityTracker;
            // 计算当前的速度
            velocityTracker.computeCurrentVelocity(1000);
            // 获得当前的速度
            int velocityX = (int) velocityTracker.getXVelocity();


            if (velocityX > SNAP_VELOCITY && mCurScreen > 0) {
                // Fling enough to move left
                snapToScreen(mCurScreen - 1);
            } else if (velocityX < -SNAP_VELOCITY
                    && mCurScreen < getChildCount() - 1) {
                // Fling enough to move right
                snapToScreen(mCurScreen + 1);
            } else {
                snapToDestination();
            }

            if (mVelocityTracker != null) {
                mVelocityTracker.recycle();
                mVelocityTracker = null;
            }
            // }
            mTouchState = TOUCH_STATE_REST;
            break;
        case MotionEvent.ACTION_CANCEL:
            mTouchState = TOUCH_STATE_REST;
            break;
        }

        return true;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        // TODO Auto-generated method stub
        //Log.i(TAG, "onInterceptTouchEvent-slop:");

        final int action = ev.getAction();
        if ((action == MotionEvent.ACTION_MOVE)
                && (mTouchState != TOUCH_STATE_REST)) {
            return true;
        }

        final float x = ev.getX();

        switch (action) {
        case MotionEvent.ACTION_MOVE:
            final int xDiff = (int) Math.abs(mLastMotionX - x);
            if (xDiff > mTouchSlop) {
                mTouchState = TOUCH_STATE_SCROLLING;

            }
            break;

        case MotionEvent.ACTION_DOWN:
            mNum = new Random().nextInt(5);
            mLastMotionX = x;
            mTouchState = mScroller.isFinished() ? TOUCH_STATE_REST
                    : TOUCH_STATE_SCROLLING;
            break;

        case MotionEvent.ACTION_CANCEL:
        case MotionEvent.ACTION_UP:
            mTouchState = TOUCH_STATE_REST;
            break;
        }

        return mTouchState != TOUCH_STATE_REST;
    }

    class BigStone {
        //图片
        Bitmap bitmap;
        //角度
        int angle;
        //x坐标
        float x;
        //y坐标
        float y;
        //是否可见
        String text;
        boolean isVisible = true;
    }
}
View Code

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

posted on 2013-06-07 11:40  大米稀饭  阅读(413)  评论(0编辑  收藏  举报