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幅度越小,反之則反之。
好了下面開始代碼:
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ò)程。縮放的梯度就用到了文章開始介紹的小知識(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熱修復(fù)技術(shù)原理之so庫(kù)熱修復(fù)技術(shù)
通常情況下,大多數(shù)人希望android下熱補(bǔ)丁方案能夠做到補(bǔ)丁的全方位修復(fù),包括類修復(fù)/資源修復(fù)/so庫(kù)的修復(fù)。 這里主要介紹熱補(bǔ)丁之so庫(kù)修復(fù)思路2021-06-06Android應(yīng)用程序的編譯流程及使用Ant編譯項(xiàng)目的攻略
這篇文章主要介紹了Android應(yīng)用程序的編譯流程及使用Ant編譯項(xiàng)目的攻略,Ant是集編譯測(cè)試部署于一體的Java自動(dòng)化工具,要的朋友可以參考下2016-04-04Android中l(wèi)istview嵌套scrollveiw沖突的解決方法
這篇文章主要為大家詳細(xì)介紹了Android中l(wèi)istview嵌套scrollveiw沖突的解決方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-01-01Android應(yīng)用中設(shè)置alpha值來(lái)制作透明與漸變效果的實(shí)例
這篇文章主要介紹了Android應(yīng)用中設(shè)置alpha值來(lái)制作透明與漸變效果的實(shí)例,展示了基礎(chǔ)的透明漸變動(dòng)畫的編寫方法,需要的朋友可以參考下2016-04-04Android Jetpack組件DataBinding詳解
這篇文章主要介紹了Android Jetpack組件DataBinding,DataBinding有很多優(yōu)勢(shì),其中最明顯是代碼更加簡(jiǎn)潔,可讀性會(huì)更高。部分和UI控件有關(guān)的代碼可以在布局文件當(dāng)中完成,本文給大家詳細(xì)講解,需要的朋友可以參考下2022-10-10Flutter實(shí)現(xiàn)抽屜動(dòng)畫
這篇文章主要為大家詳細(xì)介紹了Flutter實(shí)現(xiàn)抽屜動(dòng)畫,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03gradle tool升級(jí)到3.0注意事項(xiàng)小結(jié)
這篇文章主要介紹了gradle tool升級(jí)到3.0注意事項(xiàng)及修改相關(guān)文件介紹,需要的朋友可以參考下2018-02-02