• 自定义控件:(动画)(特效)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 + 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 + 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 + 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 + 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 + 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 +  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
  • 相关阅读:
    AndroidStudio小技巧--依赖库
    仿iOS Segmented Control样式"
    Metaweblog在Android上使用
    正则表达式使用技巧
    flask中gunicorn的使用
    Git用法小记
    指定GPU训练模型
    python中grpc的使用示例
    如何用LaTex编辑数学公式
    keras使用多进程
  • 原文地址:https://www.cnblogs.com/androidsj/p/3123551.html
Copyright © 2020-2023  润新知