Android仿Win8的metro的UI界面(上)
手機(jī)下載了一些APP,發(fā)現(xiàn)現(xiàn)在仿win8的主界面越來(lái)越多,在大家見(jiàn)慣了類GridView或者類Tab后,給人一種耳目一新的感覺(jué)。今天在eoe上偶然發(fā)現(xiàn)已經(jīng)有人實(shí)現(xiàn)了這個(gè)功能的源碼(地址:http://www.eoeandroid.com/forum.php?mod=viewthread&tid=327557),馬上下載跑了一下,效果很炫,但是有些bug,比如點(diǎn)擊速度特別快時(shí)圖像會(huì)被放大,以及點(diǎn)擊時(shí)會(huì)觸發(fā)兩次點(diǎn)擊事件。
本例子基于eoe中這位大神的實(shí)現(xiàn),做了一些簡(jiǎn)化,和bug的修復(fù)。
效果:

首先普及一個(gè)小知識(shí)點(diǎn):
我們?cè)陧?xiàng)目中有時(shí)候需要一個(gè)緩慢的梯度數(shù)據(jù),例如:控件的寬度以一定的比例增加,然后以相同的比例還原到原來(lái)的長(zhǎng)度。
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++;
}
}
}
輸出結(jié)果:
1.0
1.0846523
1.1764706
1.2760615
1.384083
1.5012488
1.384083
1.2760615
1.1764706
1.0846523
1.0
很完美吧,基本是個(gè)對(duì)稱的梯度數(shù)據(jù),梯度的幅度由代碼中的s覺(jué)得,越接近1幅度越小,反之則反之。
好了下面開(kāi)始代碼:
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>
布局文件,完成了上面效果圖的靜態(tài)效果,如果你不需要添加點(diǎn)擊動(dòng)畫,或者只需要很簡(jiǎn)單的點(diǎn)擊效果,那么就已經(jīng)完成這樣的菜單的編寫,再添加個(gè)backgroud自定義下點(diǎn)擊效果就好了。當(dāng)然,我們這里有個(gè)比較柔和的點(diǎn)擊動(dòng)畫,有自定義的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;
/**
* 設(shè)置一個(gè)縮放的常量
*/
private float mMinScale = 0.85f;
/**
* 縮放是否結(jié)束
*/
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;
/**
* 是否已經(jīng)調(diào)用了點(diǎn)擊事件
*/
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);
}
/**
* 回調(diào)接口
*/
private OnViewClickListener mOnViewClickListener;
public void setOnClickIntent(OnViewClickListener onViewClickListener)
{
this.mOnViewClickListener = onViewClickListener;
}
public interface OnViewClickListener
{
void onViewClick(MyImageView view);
}
}
代碼不算復(fù)雜,主要就是對(duì)onTouchEvent的Action_Down和Action_Up的監(jiān)聽(tīng),然后通過(guò)Handler結(jié)合matrix完成縮放的效果。這里簡(jiǎn)單說(shuō)一個(gè)mScaleHandler里面代碼的邏輯,當(dāng)檢測(cè)到ACTION_DOWN事件,會(huì)判斷當(dāng)前縮放是否完成,如果完成了則添加縮小的效果,如果沒(méi)有,則一直檢測(cè)。ACTION_UP也是同樣的過(guò)程??s放的梯度就用到了文章開(kāi)始介紹的小知識(shí)點(diǎn)。
有人會(huì)覺(jué)得使用Handler比較麻煩,這里一直使用Handler.sendMsg的原因是,利用了這個(gè)消息隊(duì)列,隊(duì)列先進(jìn)先出,保證動(dòng)畫效果的流暢。因?yàn)锳CTION_DOWN_與ACTION_UP一瞬點(diǎn)完成的,其實(shí)動(dòng)畫還在進(jìn)行。如果你在onTouchEvent中用while集合sleep完成動(dòng)畫,會(huì)出現(xiàn)卡死,監(jiān)聽(tīng)不到Up事件等問(wèn)題。
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();
}
});
}
}
利用提供的回調(diào)接口注冊(cè)了點(diǎn)擊事件。這里說(shuō)明一下,現(xiàn)在為ImageView設(shè)置OnClickLIstener是沒(méi)有作用的,因?yàn)樽远x的ImageView的onTouchEvent直接返回了true,不會(huì)往下執(zhí)行click事件,如果你希望通過(guò)OnClickLIstener進(jìn)行注冊(cè),你可以把ontouchevent里面返回值改成super.ontouchevent(event),并且需要將ImageView的clickable設(shè)置為true。這些都是Ontouch事件的傳播機(jī)制,不了解的google下,還是很有必要的。
源碼下載:http://xiazai.jb51.net/201608/yuanma/AndroidRolateAnim(jb51.net).rar
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android應(yīng)用中拍照后獲取照片路徑并上傳的實(shí)例分享
這篇文章主要介紹了Android應(yīng)用中拍照后獲取照片路徑并上傳的實(shí)例分享,文中使用MultipartEntityBuilder制作了一個(gè)簡(jiǎn)單的上傳工具,需要的朋友可以參考下2016-03-03
Android不使用自定義布局情況下實(shí)現(xiàn)自定義通知欄圖標(biāo)的方法
這篇文章主要介紹了Android不使用自定義布局情況下實(shí)現(xiàn)自定義通知欄圖標(biāo)的方法,實(shí)例分析了Android通知欄圖標(biāo)的創(chuàng)建技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-12-12
Android編程實(shí)現(xiàn)調(diào)用系統(tǒng)圖庫(kù)與裁剪圖片功能
這篇文章主要介紹了Android編程實(shí)現(xiàn)調(diào)用系統(tǒng)圖庫(kù)與裁剪圖片功能,結(jié)合實(shí)例形式分析了Android針對(duì)圖形的旋轉(zhuǎn)與剪切等具體操作技巧,需要的朋友可以參考下2017-01-01
Android啟動(dòng)優(yōu)化之延時(shí)加載的步驟詳解
這篇文章主要給大家介紹了關(guān)于Android啟動(dòng)優(yōu)化之延時(shí)加載的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-02-02
android隱式意圖激活自定義界面和系統(tǒng)應(yīng)用界面的實(shí)例
下面小編就為大家?guī)?lái)一篇android隱式意圖激活自定義界面和系統(tǒng)應(yīng)用界面的實(shí)例。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-06-06
Android編程實(shí)現(xiàn)攝像頭臨摹效果的方法
這篇文章主要介紹了Android編程實(shí)現(xiàn)攝像頭臨摹效果的方法,涉及Android權(quán)限控制、布局及攝像頭功能調(diào)用等相關(guān)操作技巧,需要的朋友可以參考下2017-09-09
Android開(kāi)發(fā)之APP安裝后在桌面上不顯示應(yīng)用圖標(biāo)的解決方法
這篇文章主要介紹了Android開(kāi)發(fā)之APP安裝后在桌面上不顯示應(yīng)用圖標(biāo)的解決方法,涉及Android activity相關(guān)屬性設(shè)置技巧,需要的朋友可以參考下2017-07-07
Android 系統(tǒng)語(yǔ)言切換監(jiān)聽(tīng)和設(shè)置實(shí)例代碼
本篇文章主要介紹了Android 系統(tǒng)語(yǔ)言切換監(jiān)聽(tīng)和設(shè)置實(shí)例代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-06-06
android使用PopupWindow實(shí)現(xiàn)頁(yè)面點(diǎn)擊頂部彈出下拉菜單
這篇文章主要給大家介紹android使用PopupWindow實(shí)現(xiàn)頁(yè)面點(diǎn)擊頂部彈出下拉菜單,實(shí)現(xiàn)此功能主要通過(guò)PopupWindow方法,代碼也很簡(jiǎn)單,需要的朋友可以參考下2015-08-08
Android 驗(yàn)證碼功能實(shí)現(xiàn)代碼
這篇文章主要介紹了Android 驗(yàn)證碼功能實(shí)現(xiàn)代碼的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-08-08

