Android 仿Win8的metro的UI界面(上)

转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/23441455

昨晚没事手机下载了一些APP,发现现在仿win8的主界面越来越多,在大家见惯了类GridView或者类Tab后,给人一种耳目一新的感觉。今天在eoe上偶然发现已经有人实现了这个功能的源码(地址:http://www.eoeandroid.com/forum.php?mod=viewthread&tid=327557),马上下载跑了一下,效果很炫,但是有些bug,比如点击速度特别快时图像会被放大,以及点击时会触发两次点击事件。

本例子基于eoe中这位大神的实现,做了一些简化,和bug的修复。

效果:

Android 仿Win8的metro的UI界面(上)

首先普及一个小知识点:

我们在项目中有时候需要一个缓慢的梯度数据,例如:控件的宽度以一定的比例增加,然后以相同的比例还原到原来的长度。

 

[java] view plaincopyAndroid 仿Win8的metro的UI界面(上)Android 仿Win8的metro的UI界面(上)
 
  1. package com.zhy._01;  
  2.   
  3. public class Test2  
  4. {  
  5.     public static void main(String[] args)  
  6.     {  
  7.         float val = 1;   
  8.         float s = 0.85f;  
  9.         int i = 0;  
  10.         s = (float) Math.sqrt(1 / s);  
[java] view plaincopyAndroid 仿Win8的metro的UI界面(上)Android 仿Win8的metro的UI界面(上)
 
  1.                System.out.println(val);  
  2.     while (i < 5)  
  3.     {  
  4.         val = val *s ;  
  5.         System.out.println(val);  
  6.         i++;  
  7.     }  
  8.      s = 0.85f;  
  9.     i = 0;  
  10.     s = (float) Math.sqrt(s);  
  11.     while (i < 5)  
  12.     {  
  13.         val = val *s ;  
  14.         System.out.println(val);  
  15.         i++;  
  16.     }  
  17.   
  18. }  


输出结果:

 

 

[java] view plaincopyAndroid 仿Win8的metro的UI界面(上)Android 仿Win8的metro的UI界面(上)
 
  1. 1.0  
  2. 1.0846523  
  3. 1.1764706  
  4. 1.2760615  
  5. 1.384083  
  6. 1.5012488  
  7. 1.384083  
  8. 1.2760615  
  9. 1.1764706  
  10. 1.0846523  
  11. 1.0  


很完美吧,基本是个对称的梯度数据,梯度的幅度由代码中的s觉得,越接近1幅度越小,反之则反之。

 

 

好了下面开始代码:

1、布局文件

 

[html] view plaincopyAndroid 仿Win8的metro的UI界面(上)Android 仿Win8的metro的UI界面(上)
 
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:layout_width="fill_parent"  
  4.     android:layout_height="fill_parent"  
  5.     android:background="@drawable/bkg_img_default"  
  6.     android:gravity="center"  
  7.     android:orientation="vertical" >  
  8.   
  9.     <LinearLayout  
  10.         android:layout_width="wrap_content"  
  11.         android:layout_height="wrap_content"  
  12.         android:orientation="vertical" >  
  13.   
  14.         <LinearLayout  
  15.             android:layout_width="wrap_content"  
  16.             android:layout_height="wrap_content"  
  17.             android:orientation="horizontal" >  
  18.   
  19.             <LinearLayout  
  20.                 android:layout_width="wrap_content"  
  21.                 android:layout_height="wrap_content"  
  22.                 android:orientation="vertical" >  
  23.   
  24.                 <com.ljp.ani01.MyImageView  
  25.                     android:id="@+id/c_joke"  
  26.                     android:layout_width="wrap_content"  
  27.                     android:layout_height="wrap_content"  
  28.                     android:layout_margin="2dp"  
  29.                     android:scaleType="matrix"  
  30.                     android:src="@drawable/left_top" />  
  31.   
  32.                 <com.ljp.ani01.MyImageView  
  33.                     android:id="@+id/c_idea"  
  34.                     android:layout_width="wrap_content"  
  35.                     android:layout_height="wrap_content"  
  36.                     android:layout_margin="2dp"  
  37.                     android:scaleType="matrix"  
  38.                     android:src="@drawable/left_bottom" />  
  39.             </LinearLayout>  
  40.   
  41.             <com.ljp.ani01.MyImageView  
  42.                 android:id="@+id/c_constellation"  
  43.                 android:layout_width="wrap_content"  
  44.                 android:layout_height="wrap_content"  
  45.                 android:layout_margin="2dp"  
  46.                 android:scaleType="matrix"  
  47.                 android:src="@drawable/right" />  
  48.         </LinearLayout>  
  49.   
  50.         <com.ljp.ani01.MyImageView  
  51.             android:id="@+id/c_recommend"  
  52.             android:layout_width="wrap_content"  
  53.             android:layout_height="wrap_content"  
  54.             android:layout_margin="2dp"  
  55.             android:scaleType="matrix"  
  56.             android:src="@drawable/bottom" />  
  57.     </LinearLayout>  
  58.   
  59. </LinearLayout>  


布局文件,完成了上面效果图的静态效果,如果你不需要添加点击动画,或者只需要很简单的点击效果,那么就已经完成这样的菜单的编写,再添加个backgroud自定义下点击效果就好了。当然,我们这里有个比较柔和的点击动画,有自定义的ImageView完成。

 

2、MyImageView.java

 

[java] view plaincopyAndroid 仿Win8的metro的UI界面(上)Android 仿Win8的metro的UI界面(上)
 
  1. package com.ljp.ani01;  
  2.   
  3. import android.content.Context;  
  4. import android.graphics.Matrix;  
  5. import android.graphics.drawable.BitmapDrawable;  
  6. import android.graphics.drawable.Drawable;  
  7. import android.os.Handler;  
  8. import android.util.AttributeSet;  
  9. import android.util.Log;  
  10. import android.view.MotionEvent;  
  11. import android.widget.ImageView;  
  12.   
  13. public class MyImageView extends ImageView  
  14. {  
  15.   
  16.     private static final String TAG = "MyImageView";  
  17.   
  18.     private static final int SCALE_REDUCE_INIT = 0;  
  19.     private static final int SCALING = 1;  
  20.     private static final int SCALE_ADD_INIT = 6;  
  21.   
  22.     /** 
  23.      * 控件的宽 
  24.      */  
  25.     private int mWidth;  
  26.     /** 
  27.      * 控件的高 
  28.      */  
  29.     private int mHeight;  
  30.     /** 
  31.      * 控件的宽1/2 
  32.      */  
  33.     private int mCenterWidth;  
  34.     /** 
  35.      * 控件的高 1/2 
  36.      */  
  37.     private int mCenterHeight;  
  38.     /** 
  39.      * 设置一个缩放的常量 
  40.      */  
  41.     private float mMinScale = 0.85f;  
  42.     /** 
  43.      * 缩放是否结束 
  44.      */  
  45.     private boolean isFinish = true;  
  46.   
  47.     public MyImageView(Context context)  
  48.     {  
  49.         this(context, null);  
  50.     }  
  51.   
  52.     public MyImageView(Context context, AttributeSet attrs)  
  53.     {  
  54.         this(context, attrs, 0);  
  55.     }  
  56.   
  57.     public MyImageView(Context context, AttributeSet attrs, int defStyle)  
  58.     {  
  59.         super(context, attrs, defStyle);  
  60.     }  
  61.   
  62.     /** 
  63.      * 必要的初始化 
  64.      */  
  65.     @Override  
  66.     protected void onLayout(boolean changed, int left, int top, int right, int bottom)  
  67.     {  
  68.         super.onLayout(changed, left, top, right, bottom);  
  69.         if (changed)  
  70.         {  
  71.             mWidth = getWidth() - getPaddingLeft() - getPaddingRight();  
  72.             mHeight = getHeight() - getPaddingTop() - getPaddingBottom();  
  73.   
  74.             mCenterWidth = mWidth / 2;  
  75.             mCenterHeight = mHeight / 2;  
  76.   
  77.             Drawable drawable = getDrawable();  
  78.             BitmapDrawable bd = (BitmapDrawable) drawable;  
  79.             bd.setAntiAlias(true);  
  80.         }  
  81.     }  
  82.   
  83.     @Override  
  84.     public boolean onTouchEvent(MotionEvent event)  
  85.     {  
  86.         switch (event.getAction())  
  87.         {  
  88.         case MotionEvent.ACTION_DOWN:  
  89.             float X = event.getX();  
  90.             float Y = event.getY();  
  91.             mScaleHandler.sendEmptyMessage(SCALE_REDUCE_INIT);  
  92.             break;  
  93.         case MotionEvent.ACTION_UP:  
  94.             mScaleHandler.sendEmptyMessage(SCALE_ADD_INIT);  
  95.             break;  
  96.         }  
  97.         return true;  
  98.     }  
  99.   
  100.     /** 
  101.      * 控制缩放的Handler 
  102.      */  
  103.     private Handler mScaleHandler = new Handler()  
  104.     {  
  105.         private Matrix matrix = new Matrix();  
  106.         private int count = 0;  
  107.         private float s;  
  108.         /** 
  109.          * 是否已经调用了点击事件 
  110.          */  
  111.         private boolean isClicked;  
  112.   
  113.         public void handleMessage(android.os.Message msg)  
  114.         {  
  115.             matrix.set(getImageMatrix());  
  116.             switch (msg.what)  
  117.             {  
  118.             case SCALE_REDUCE_INIT:  
  119.                 if (!isFinish)  
  120.                 {  
  121.                     mScaleHandler.sendEmptyMessage(SCALE_REDUCE_INIT);  
  122.                 } else  
  123.                 {  
  124.                     isFinish = false;  
  125.                     count = 0;  
  126.                     s = (float) Math.sqrt(Math.sqrt(mMinScale));  
  127.                     beginScale(matrix, s);  
  128.                     mScaleHandler.sendEmptyMessage(SCALING);  
  129.                 }  
  130.                 break;  
  131.             case SCALING:  
  132.                 beginScale(matrix, s);  
  133.                 if (count < 4)  
  134.                 {  
  135.                     mScaleHandler.sendEmptyMessage(SCALING);  
  136.                 } else  
  137.                 {  
  138.                     isFinish = true;  
  139.                     if (MyImageView.this.mOnViewClickListener != null && !isClicked)  
  140.                     {  
  141.                         isClicked = true;  
  142.                         MyImageView.this.mOnViewClickListener.onViewClick(MyImageView.this);  
  143.                     } else  
  144.                     {  
  145.                         isClicked = false;  
  146.                     }  
  147.                 }  
  148.                 count++;  
  149.   
  150.                 break;  
  151.             case 6:  
  152.                 if (!isFinish)  
  153.                 {  
  154.                     mScaleHandler.sendEmptyMessage(SCALE_ADD_INIT);  
  155.                 } else  
  156.                 {  
  157.                     isFinish = false;  
  158.                     count = 0;  
  159.                     s = (float) Math.sqrt(Math.sqrt(1.0f / mMinScale));  
  160.                     beginScale(matrix, s);  
  161.                     mScaleHandler.sendEmptyMessage(SCALING);  
  162.                 }  
  163.                 break;  
  164.             }  
  165.         }  
  166.     };  
  167.   
  168.     protected void sleep(int i)  
  169.     {  
  170.         try  
  171.         {  
  172.             Thread.sleep(i);  
  173.         } catch (InterruptedException e)  
  174.         {  
  175.             e.printStackTrace();  
  176.         }  
  177.     }  
  178.   
  179.     /** 
  180.      * 缩放 
  181.      *  
  182.      * @param matrix 
  183.      * @param scale 
  184.      */  
  185.     private synchronized void beginScale(Matrix matrix, float scale)  
  186.     {  
  187.         matrix.postScale(scale, scale, mCenterWidth, mCenterHeight);  
  188.         setImageMatrix(matrix);  
  189.     }  
  190.   
  191.     /** 
  192.      * 回调接口 
  193.      */  
  194.     private OnViewClickListener mOnViewClickListener;  
  195.   
  196.     public void setOnClickIntent(OnViewClickListener onViewClickListener)  
  197.     {  
  198.         this.mOnViewClickListener = onViewClickListener;  
  199.     }  
  200.   
  201.     public interface OnViewClickListener  
  202.     {  
  203.         void onViewClick(MyImageView view);  
  204.     }  
  205.   
  206. }  

代码不算复杂,主要就是对onTouchEvent的Action_Down和Action_Up的监听,然后通过Handler结合matrix完成缩放的效果。这里简单说一个mScaleHandler里面代码的逻辑,当检测到ACTION_DOWN事件,会判断当前缩放是否完成,如果完成了则添加缩小的效果,如果没有,则一直检测。ACTION_UP也是同样的过程。缩放的梯度就用到了文章开始介绍的小知识点。

 

有人会觉得使用Handler比较麻烦,这里一直使用Handler.sendMsg的原因是,利用了这个消息队列,队列先进先出,保证动画效果的流畅。因为ACTION_DOWN_与ACTION_UP一瞬点完成的,其实动画还在进行。如果你在onTouchEvent中用while集合sleep完成动画,会出现卡死,监听不到Up事件等问题。


3、主Activity

 

[java] view plaincopyAndroid 仿Win8的metro的UI界面(上)Android 仿Win8的metro的UI界面(上)
 
  1. package com.ljp.ani01;  
  2.   
  3. import android.app.Activity;  
  4. import android.os.Bundle;  
  5. import android.view.View;  
  6. import android.view.View.OnClickListener;  
  7. import android.widget.Toast;  
  8.   
  9. public class TestRolateAnimActivity extends Activity  
  10. {  
  11.     MyImageView joke;  
  12.   
  13.     @Override  
  14.     public void onCreate(Bundle savedInstanceState)  
  15.     {  
  16.         super.onCreate(savedInstanceState);  
  17.         setContentView(R.layout.main);  
  18.   
  19.         joke = (MyImageView) findViewById(R.id.c_joke);  
  20.         joke.setOnClickIntent(new MyImageView.OnViewClickListener()  
  21.         {  
  22.   
  23.             @Override  
  24.             public void onViewClick(MyImageView view)  
  25.             {  
  26.                 Toast.makeText(TestRolateAnimActivity.this, "Joke", 1000).show();  
  27.             }  
  28.         });  
  29.     }  
  30.       
  31.       
  32. }  


利用提供的回调接口注册了点击事件。这里说明一下,现在为ImageView设置OnClickLIstener是没有作用的,因为自定义的ImageView的onTouchEvent直接返回了true,不会往下执行click事件,如果你希望通过OnClickLIstener进行注册,你可以把ontouchevent里面返回值改成super.ontouchevent(event),并且需要将ImageView的clickable设置为true。这些都是Ontouch事件的传播机制,不了解的google下,还是很有必要的。

 

 

如果你觉得这篇文章对你有用,可以顶一个~~

 

源码下载点击此处

 

Android 仿Win8的metro的UI界面(上)

上一篇:iOS开发XCODE5 SVN配置 使用办法


下一篇:美国最受欢迎的25个App都是哪些?