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


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


    源码下载点击此处






    版权声明:本文为博主原创文章,未经博主允许不得转载。

  • 相关阅读:
    RN-Android构建失败:Caused by: org.gradle.api.ProjectConfigurationException: A problem occurred configuring root project 'AwesomeProject'.
    Android更新包下载成功后不出现安装界面
    真机调试: The application could not be installed: INSTALL_FAILED_TEST_ONLY
    react native 屏幕尺寸转换
    Android Studio生成签名文件,自动签名,以及获取SHA1和MD5值
    React Native安卓真机调试
    git提交代码报错Permission denied, please try again
    The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.
    命令行设置快捷命令
    Linux 常用指令
  • 原文地址:https://www.cnblogs.com/dingxiaoyue/p/4924995.html
Copyright © 2011-2022 走看看