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

Wesley13
• 阅读 652

《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();
            }
        });
    }
}
点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
待兔 待兔
5个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Stella981 Stella981
3年前
Sass
嵌套规则(NestedRules)Sass允许将一套CSS样式嵌套进另一套样式中,内层的样式将它外层的选择器作为父选择器mainp{color:00ff00;width:97%;.redbox{
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
3年前
Android蓝牙连接汽车OBD设备
//设备连接public class BluetoothConnect implements Runnable {    private static final UUID CONNECT_UUID  UUID.fromString("0000110100001000800000805F9B34FB");
Wesley13 Wesley13
3年前
Unity横屏
Android下发现Unity里面的Player设置,并不能完全有效,比如打开了自动旋转,启动的时候还是会横屏,修改XML添加以下代码<applicationandroid:icon"@drawable/ic\_launcher"                    android:label"@string/app\_name"
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
11个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这