zoukankan      html  css  js  c++  java
  • 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的修复。

    效果:

    首先普及一个小知识点:

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

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


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


    源码下载点击此处






  • 相关阅读:
    SQLite学习第02天:数据类型
    SQLite学习第01天:参考资料
    利用OllyDebug查看程序调用的dll模块
    Qt文件信息获取之QFileInfo
    Qt标准对话框之QColorDialog
    Windows平台下Qt开发环境的搭建
    何时使用引用参数(转)
    OpenCV2学习笔记01:Linux下OpenCV开发环境的搭建
    node实现缓存
    node进阶之用流实现上传文件
  • 原文地址:https://www.cnblogs.com/oversea201405/p/3752048.html
Copyright © 2011-2022 走看看