您的位置:首页 > 产品设计 > UI/UE

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

2014-05-30 15:46 323 查看
转载请标明出处: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的修复。

效果:



首先普及一个小知识点:

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

[java] view
plaincopy





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);

[java] view
plaincopy





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++;

}



}

输出结果:

[java] view
plaincopy





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、布局文件

[html] view
plaincopy





<?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

[java] view
plaincopy





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

[java] view
plaincopy





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下,还是很有必要的。

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


源码下载点击此处

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: