Android实现Windows 8磁贴(Tile)样式按钮

《Android实现Windows 8磁贴(Tile)样式按钮》

效果图如下:

我在网上流传的代码基础上精简、整理出一个简单的类,我暂时把它命名为:Windows8TileImageView,即Windows 8磁贴(Tile)样式按钮,Windows8TileImageView其实就是继承于标准Android ImageView,单击该Windows8TileImageView有收缩、侧边收缩等比较有趣的效果。现在把Windows8TileImageView这个类的全部代码贴出来:

package windows8.tile;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Camera;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PaintFlagsDrawFilter;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.ImageView;

public class Windows8TileImageView extends ImageView {
	public static final int Rotate_Handler_Message_Start = 1;
	public static final int Rotate_Handler_Message_Turning = 2;
	public static final int Rotate_Handler_Message_Turned = 3;
	public static final int Rotate_Handler_Message_Reverse = 6;

	public static final int Scale_Handler_Message_Start = 1;
	public static final int Scale_Handler_Message_Turning = 2;
	public static final int Scale_Handler_Message_Turned = 3;
	public static final int Scale_Handler_Message_Reverse = 6;

	private boolean isAntiAlias = true;
	private boolean scaleOnly = false;
	private boolean isSizeChanged = false;
	private boolean isShowAnimation = true;
	private int rotateDegree = 10;
	private boolean isFirst = true;
	private float minScale = 0.95f;
	private int vWidth;
	private int vHeight;
	private boolean isAnimationFinish = true, isActionMove = false,
			isScale = false;
	private Camera camera;
	boolean XbigY = false;
	float RolateX = 0;
	float RolateY = 0;
	OnViewClick onclick = null;

	public Windows8TileImageView(Context context) {
		super(context);
		camera = new Camera();
	}

	public Windows8TileImageView(Context context, AttributeSet attrs) {
		super(context, attrs);
		camera = new Camera();
	}

	public void SetAnimationOnOff(boolean oo) {
		isShowAnimation = oo;
	}

	public void setOnClickIntent(OnViewClick onclick) {
		this.onclick = onclick;
	}

	@SuppressLint("DrawAllocation")
	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		if (isFirst) {
			isFirst = false;
			init();
		}
		canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG
				| Paint.FILTER_BITMAP_FLAG));
	}

	public void init() {
		vWidth = getWidth() - getPaddingLeft() - getPaddingRight();
		vHeight = getHeight() - getPaddingTop() - getPaddingBottom();
		Drawable drawable = getDrawable();
		BitmapDrawable bd = (BitmapDrawable) drawable;
		bd.setAntiAlias(isAntiAlias);
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		super.onTouchEvent(event);
		if (!isShowAnimation)
			return true;

		switch (event.getAction() & MotionEvent.ACTION_MASK) {
		case MotionEvent.ACTION_DOWN:
			float X = event.getX();
			float Y = event.getY();
			RolateX = vWidth / 2 - X;
			RolateY = vHeight / 2 - Y;
			XbigY = Math.abs(RolateX) > Math.abs(RolateY) ? true : false;

			isScale = X > vWidth / 3 && X < vWidth * 2 / 3 && Y > vHeight / 3
					&& Y < vHeight * 2 / 3;
			isActionMove = false;

			if (isScale) {
				if (isAnimationFinish && !isSizeChanged) {
					isSizeChanged = true;
					scale_handler.sendEmptyMessage(Scale_Handler_Message_Start);
				}
			} else {
				if (scaleOnly) {
					scale_handler.sendEmptyMessage(Scale_Handler_Message_Start);
				} else {
					rotate_Handler
							.sendEmptyMessage(Rotate_Handler_Message_Start);
				}
			}
			break;
		case MotionEvent.ACTION_MOVE:
			float x = event.getX();
			float y = event.getY();
			if (x > vWidth || y > vHeight || x < 0 || y < 0) {
				isActionMove = true;
			} else {
				isActionMove = false;
			}

			break;
		case MotionEvent.ACTION_UP:
			if (isScale) {
				if (isSizeChanged)
					scale_handler
							.sendEmptyMessage(Scale_Handler_Message_Reverse);
			} else {
				rotate_Handler.sendEmptyMessage(Rotate_Handler_Message_Reverse);
			}
			break;
		}
		return true;
	}

	public interface OnViewClick {
		public void onClick();
	}

	@SuppressLint("HandlerLeak")
	private Handler rotate_Handler = new Handler() {
		private Matrix matrix = new Matrix();
		private float count = 0;

		// private boolean clickGuolv = false;
		@Override
		public void handleMessage(Message msg) {
			super.handleMessage(msg);
			matrix.set(getImageMatrix());
			switch (msg.what) {
			case Rotate_Handler_Message_Start:
				count = 0;
				beginRotate(matrix, (XbigY ? count : 0), (XbigY ? 0 : count));
				rotate_Handler.sendEmptyMessage(Rotate_Handler_Message_Turning);
				break;
			case Rotate_Handler_Message_Turning:
				beginRotate(matrix, (XbigY ? count : 0), (XbigY ? 0 : count));
				count++;
				if (count < getDegree()) {
					rotate_Handler
							.sendEmptyMessage(Rotate_Handler_Message_Turning);
				} else {
					isAnimationFinish = true;
				}
				break;
			case Rotate_Handler_Message_Turned:
				beginRotate(matrix, (XbigY ? count : 0), (XbigY ? 0 : count));
				if (count > 0) {
					rotate_Handler
							.sendEmptyMessage(Rotate_Handler_Message_Turned);
				} else {
					isAnimationFinish = true;
					if (!isActionMove && onclick != null) {
						onclick.onClick();
					}
				}
				count--;
				count--;
				break;
			case Rotate_Handler_Message_Reverse:
				count = getDegree();
				beginRotate(matrix, (XbigY ? count : 0), (XbigY ? 0 : count));
				rotate_Handler.sendEmptyMessage(Rotate_Handler_Message_Turned);
				break;
			}
		}
	};

	private synchronized void beginRotate(Matrix matrix, float rotateX,
			float rotateY) {
		// Bitmap bm = getImageBitmap();
		int scaleX = (int) (vWidth * 0.5f);
		int scaleY = (int) (vHeight * 0.5f);
		camera.save();
		camera.rotateX(RolateY > 0 ? rotateY : -rotateY);
		camera.rotateY(RolateX < 0 ? rotateX : -rotateX);
		camera.getMatrix(matrix);
		camera.restore();
		// 控制中心点
		if (RolateX > 0 && rotateX != 0) {
			matrix.preTranslate(-vWidth, -scaleY);
			matrix.postTranslate(vWidth, scaleY);
		} else if (RolateY > 0 && rotateY != 0) {
			matrix.preTranslate(-scaleX, -vHeight);
			matrix.postTranslate(scaleX, vHeight);
		} else if (RolateX < 0 && rotateX != 0) {
			matrix.preTranslate(-0, -scaleY);
			matrix.postTranslate(0, scaleY);
		} else if (RolateY < 0 && rotateY != 0) {
			matrix.preTranslate(-scaleX, -0);
			matrix.postTranslate(scaleX, 0);
		}
		setImageMatrix(matrix);
	}

	private Handler scale_handler = new Handler() {
		private Matrix matrix = new Matrix();
		private float s;
		int count = 0;

		@Override
		public void handleMessage(Message msg) {
			super.handleMessage(msg);
			matrix.set(getImageMatrix());
			switch (msg.what) {
			case Scale_Handler_Message_Start:
				if (!isAnimationFinish) {
					return;
				} else {
					isAnimationFinish = false;
					isSizeChanged = true;
					count = 0;
					s = (float) Math.sqrt(Math.sqrt(minScale));
					beginScale(matrix, s);
					scale_handler
							.sendEmptyMessage(Scale_Handler_Message_Turning);
				}
				break;
			case Scale_Handler_Message_Turning:
				beginScale(matrix, s);
				if (count < 4) {
					scale_handler
							.sendEmptyMessage(Scale_Handler_Message_Turning);
				} else {
					isAnimationFinish = true;
					if (!isSizeChanged && !isActionMove && onclick != null) {
						onclick.onClick();
					}
				}
				count++;
				break;
			case Scale_Handler_Message_Reverse:
				if (!isAnimationFinish) {
					scale_handler
							.sendEmptyMessage(Scale_Handler_Message_Reverse);
				} else {
					isAnimationFinish = false;
					count = 0;
					s = (float) Math.sqrt(Math.sqrt(1.0f / minScale));
					beginScale(matrix, s);
					scale_handler
							.sendEmptyMessage(Scale_Handler_Message_Turning);
					isSizeChanged = false;
				}
				break;
			}
		}
	};

	private synchronized void beginScale(Matrix matrix, float scale) {
		int scaleX = (int) (vWidth * 0.5f);
		int scaleY = (int) (vHeight * 0.5f);
		matrix.postScale(scale, scale, scaleX, scaleY);
		setImageMatrix(matrix);
	}

	public int getDegree() {
		return rotateDegree;
	}

	public void setDegree(int degree) {
		rotateDegree = degree;
	}

	public float getScale() {
		return minScale;
	}

	public void setScale(float scale) {
		minScale = scale;
	}
}

Windows8TileImageView使用方法很简单,和Android的ImageView类似,直接把它作为一个View使用。比如可以在布局文件中这样使用:

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

                <windows8.tile.Windows8TileImageView
                    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" />

                <windows8.tile.Windows8TileImageView
                    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>

            <windows8.tile.Windows8TileImageView
                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>

        <windows8.tile.Windows8TileImageView
            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>

说明:此布局文件中的 android:src加载的drawable资源图片是自己选取的,具体使用时候可以根据自身情况设置。

可以为控件Windows8TileImageView增加单击事件,比如这样添加:

package windows8.tile;

import android.support.v7.app.ActionBarActivity;
import android.widget.Toast;
import android.os.Bundle;

public class MainActivity extends ActionBarActivity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		Windows8TileImageView joke = (Windows8TileImageView) findViewById(R.id.c_joke);

		// 为某一个磁贴添加点击事件的方式。
		joke.setOnClickIntent(new Windows8TileImageView.OnViewClick() {

			@Override
			public void onClick() {
				Toast.makeText(getApplicationContext(), "磁贴的点击事件",
						Toast.LENGTH_LONG).show();
			}
		});
	}
}



时间: 2024-10-25 06:28:42

Android实现Windows 8磁贴(Tile)样式按钮的相关文章

Xamarin C# Android for Windows 安装

Xamarin C# Android for Windows  安装 Xamarin的. Android手动安装 安装Xamarin的  Android在Windows机器上   大多数时候,Xamarin的安装. Android和所需的组件是通过通用安装程序,但在某些情况下这些组件将需要手动安装. 本文将介绍所需的安装步骤和配置细节安装Xamarin的. Android平台及其先决条件在Windows组件. 安装Xamarin的工作室为Windows(可选) 安装Xamarin 3(包括Xam

十三、Android学习笔记_Andorid控件样式汇总

<!-- 设置activity为透明 --> <style name="translucent"> <item name="android:windowBackground">@color/translucent</item> <item name="android:windowIsTranslucent">true</item> <item name="an

Android学习笔记_75_Andorid控件样式汇总

<!-- 设置activity为透明 --> <style name="translucent"> <item name="android:windowBackground">@color/translucent</item> <item name="android:windowIsTranslucent">true</item> <item name="an

Android官方入门文档[7]样式化操作栏

Android官方入门文档[7]样式化操作栏 Styling the Action Bar样式化操作栏 This lesson teaches you to1.Use an Android Theme2.Customize the Background3.Customize the Text Color4.Customize the Tab Indicator You should also read?Styles and Themes?Android Action Bar Style Gene

Android自定义组合控件--底部多按钮切换

效果图: 现在市场上大多数软件都是类似于上面的结构,底部有几个按钮用于切换到不同的界面.基于OOP思想,我想把下面的一整块布局封装成一个类,也就是我们的自定义组合控件-底部多按钮切换布局,我把它叫做BottomLayout 看上面的布局,几个按钮横向排列,我们先看一下布局 最外面LinearLayout 方向 horizontal,然后5个weight相同的RelativeLayout,每个RelativeLayout里面有一个Button(用了显示选中状态)个ImageView(用来显示红点)

为Windows窗口标题栏添加新按钮

为Windows窗口标题栏添加新按钮 对于我们熟悉的标准windows窗口来讲,标题栏上一般包含有3个按钮,即最大化按钮,最小化按钮和关闭按钮.你想不想在Windows的窗口标题栏上添加一个新的自定义按钮,满足你的个性化需求,从而也使自己的窗口更具特色呢? 下面我们就讨论一下在delphi中如何给窗口的标题栏上添加新的按钮. 一.实现起来要定义以下过程: 1. 定义DrawCaptButton过程,这个过程的功能是在指定的位置画出按钮. 在过程中要使用win32函数GetSystemMetric

Bootstrap历练实例:链接样式按钮

<!DOCTYPE html><html><head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>Bootstrap历练实例:链接样式按钮</title> <meta charset="utf-8" /> <meta name="view

Android 自定义View,仿微信视频播放按钮

闲着,尝试实现了新版微信视频播放按钮,使用的是自定义View,先来个简单的效果图...真的很简单哈. 由于暂时用不到,加上时间原因,加上实在是没意思,加上……,本控件就没有实现自定义属性,有兴趣的朋友可以自己去添加一下,方法都给你们准备好了.- = 其实这个控件主要步骤 1.画外环的圆 2.画进度的圆或者画三角形播放按钮 其余剩下的都是围绕以上两步准备或者收尾的. 接下来贴主要我们的自定义控件代码,注释很全,我就不过多解释了,请各位看官自己分析,有疑问可以在评论区一起讨论. package co

android 用NineOldAndroid实现的弹出按钮

NineOldAndroid 1.首先上效果图: 左边这张是没有点击button的时候的效果,   右边这张是点击button 后是以该button为圆的展开5个button                               2.实现的思路是: 1)在FrameLayout中将6个Button进行重叠,然后将主Button显示在最上面,其他Button可以隐藏掉. 2)然后调用用NineOldAndroids来进行动画设置,在设置动画的时候要注意是以Button为中心的圆.所以要根据B