Android 仿Win8的metro的UI介面(上)
阿新 • • 發佈:2019-02-05
轉載請標明出處: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的修復。
效果:
首先普及一個小知識點:
我們在專案中有時候需要一個緩慢的梯度資料,例如:控制元件的寬度以一定的比例增加,然後以相同的比例還原到原來的長度。
package com.zhy._01;
public class Test2
{
public static void main(String[] args)
{
float val = 1;
float s = 0.85f;
int i = 0;
s = (float) Math.sqrt(1 / s);
System.out.println(val); while (i < 5) { val = val *s ; System.out.println(val); i++; } s = 0.85f; i = 0; s = (float) Math.sqrt(s); while (i < 5) { val = val *s ; System.out.println(val); i++; } } }
輸出結果:
1.0
1.0846523
1.1764706
1.2760615
1.384083
1.5012488
1.384083
1.2760615
1.1764706
1.0846523
1.0
很完美吧,基本是個對稱的梯度資料,梯度的幅度由程式碼中的s覺得,越接近1幅度越小,反之則反之。
好了下面開始程式碼:
1、佈局檔案
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="@drawable/bkg_img_default" android:gravity="center" android:orientation="vertical" > <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" > <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" > <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" > <com.ljp.ani01.MyImageView android:id="@+id/c_joke" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="2dp" android:scaleType="matrix" android:src="@drawable/left_top" /> <com.ljp.ani01.MyImageView android:id="@+id/c_idea" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="2dp" android:scaleType="matrix" android:src="@drawable/left_bottom" /> </LinearLayout> <com.ljp.ani01.MyImageView android:id="@+id/c_constellation" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="2dp" android:scaleType="matrix" android:src="@drawable/right" /> </LinearLayout> <com.ljp.ani01.MyImageView android:id="@+id/c_recommend" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="2dp" android:scaleType="matrix" android:src="@drawable/bottom" /> </LinearLayout> </LinearLayout>
佈局檔案,完成了上面效果圖的靜態效果,如果你不需要新增點選動畫,或者只需要很簡單的點選效果,那麼就已經完成這樣的選單的編寫,再添加個backgroud自定義下點選效果就好了。當然,我們這裡有個比較柔和的點選動畫,有自定義的ImageView完成。
2、MyImageView.java
package com.ljp.ani01;
import android.content.Context;
import android.graphics.Matrix;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.ImageView;
public class MyImageView extends ImageView
{
private static final String TAG = "MyImageView";
private static final int SCALE_REDUCE_INIT = 0;
private static final int SCALING = 1;
private static final int SCALE_ADD_INIT = 6;
/**
* 控制元件的寬
*/
private int mWidth;
/**
* 控制元件的高
*/
private int mHeight;
/**
* 控制元件的寬1/2
*/
private int mCenterWidth;
/**
* 控制元件的高 1/2
*/
private int mCenterHeight;
/**
* 設定一個縮放的常量
*/
private float mMinScale = 0.85f;
/**
* 縮放是否結束
*/
private boolean isFinish = true;
public MyImageView(Context context)
{
this(context, null);
}
public MyImageView(Context context, AttributeSet attrs)
{
this(context, attrs, 0);
}
public MyImageView(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
}
/**
* 必要的初始化
*/
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom)
{
super.onLayout(changed, left, top, right, bottom);
if (changed)
{
mWidth = getWidth() - getPaddingLeft() - getPaddingRight();
mHeight = getHeight() - getPaddingTop() - getPaddingBottom();
mCenterWidth = mWidth / 2;
mCenterHeight = mHeight / 2;
Drawable drawable = getDrawable();
BitmapDrawable bd = (BitmapDrawable) drawable;
bd.setAntiAlias(true);
}
}
@Override
public boolean onTouchEvent(MotionEvent event)
{
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN:
float X = event.getX();
float Y = event.getY();
mScaleHandler.sendEmptyMessage(SCALE_REDUCE_INIT);
break;
case MotionEvent.ACTION_UP:
mScaleHandler.sendEmptyMessage(SCALE_ADD_INIT);
break;
}
return true;
}
/**
* 控制縮放的Handler
*/
private Handler mScaleHandler = new Handler()
{
private Matrix matrix = new Matrix();
private int count = 0;
private float s;
/**
* 是否已經呼叫了點選事件
*/
private boolean isClicked;
public void handleMessage(android.os.Message msg)
{
matrix.set(getImageMatrix());
switch (msg.what)
{
case SCALE_REDUCE_INIT:
if (!isFinish)
{
mScaleHandler.sendEmptyMessage(SCALE_REDUCE_INIT);
} else
{
isFinish = false;
count = 0;
s = (float) Math.sqrt(Math.sqrt(mMinScale));
beginScale(matrix, s);
mScaleHandler.sendEmptyMessage(SCALING);
}
break;
case SCALING:
beginScale(matrix, s);
if (count < 4)
{
mScaleHandler.sendEmptyMessage(SCALING);
} else
{
isFinish = true;
if (MyImageView.this.mOnViewClickListener != null && !isClicked)
{
isClicked = true;
MyImageView.this.mOnViewClickListener.onViewClick(MyImageView.this);
} else
{
isClicked = false;
}
}
count++;
break;
case 6:
if (!isFinish)
{
mScaleHandler.sendEmptyMessage(SCALE_ADD_INIT);
} else
{
isFinish = false;
count = 0;
s = (float) Math.sqrt(Math.sqrt(1.0f / mMinScale));
beginScale(matrix, s);
mScaleHandler.sendEmptyMessage(SCALING);
}
break;
}
}
};
protected void sleep(int i)
{
try
{
Thread.sleep(i);
} catch (InterruptedException e)
{
e.printStackTrace();
}
}
/**
* 縮放
*
* @param matrix
* @param scale
*/
private synchronized void beginScale(Matrix matrix, float scale)
{
matrix.postScale(scale, scale, mCenterWidth, mCenterHeight);
setImageMatrix(matrix);
}
/**
* 回撥介面
*/
private OnViewClickListener mOnViewClickListener;
public void setOnClickIntent(OnViewClickListener onViewClickListener)
{
this.mOnViewClickListener = onViewClickListener;
}
public interface OnViewClickListener
{
void onViewClick(MyImageView view);
}
}
程式碼不算複雜,主要就是對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
package com.ljp.ani01;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Toast;
public class TestRolateAnimActivity extends Activity
{
MyImageView joke;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
joke = (MyImageView) findViewById(R.id.c_joke);
joke.setOnClickIntent(new MyImageView.OnViewClickListener()
{
@Override
public void onViewClick(MyImageView view)
{
Toast.makeText(TestRolateAnimActivity.this, "Joke", 1000).show();
}
});
}
}
利用提供的回撥介面註冊了點選事件。這裡說明一下,現在為ImageView設定OnClickLIstener是沒有作用的,因為自定義的ImageView的onTouchEvent直接返回了true,不會往下執行click事件,如果你希望通過OnClickLIstener進行註冊,你可以把ontouchevent裡面返回值改成super.ontouchevent(event),並且需要將ImageView的clickable設定為true。這些都是Ontouch事件的傳播機制,不瞭解的google下,還是很有必要的。
如果你覺得這篇文章對你有用,可以頂一個~~