热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

android自定义控件旋转,Android自定义控件之翻转按钮的示例代码

本文介绍了Android自定义控件之翻转按钮的示例代码,分享给大家,具体如下:先看一下效果一.先定义控件的基本结构这里我们定义一个容器&#

本文介绍了Android自定义控件之翻转按钮的示例代码,分享给大家,具体如下:

先看一下效果

6d04942ce64cb300d8cc56ba0dd384e2.gif

一.先定义控件的基本结构

这里我们定义一个容器,所以是在ViewGroup的基础上扩展。

简单起见,直接使用扩展自ViewGroup的LinearLayout,并将我们的控件扩展自LinearLayout。

1.按钮的基本布局如下

xmlns:android="http://schemas.android.com/apk/res/android"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:orientation="vertical">

android:id="@+id/mButton"

android:background="@color/colorPrimary"

android:padding="5dp"

android:layout_width="match_parent"

android:layout_height="match_parent">

android:id="@+id/buttonText"

android:text="FLIPPED BUTTON"

android:textColor="@android:color/white"

android:layout_width="wrap_content"

android:layout_height="wrap_content" />

2.自定义控件开门三步走

构造函数,onMeasure,onLayout

package net.codepig.customviewdemo.view;

import android.content.Context;

import android.util.AttributeSet;

import android.view.LayoutInflater;

import android.view.View;

import android.widget.LinearLayout;

import net.codepig.customviewdemo.R;

public class flippedButton extends LinearLayout {

private Context mContext;

private int mWidth;//容器的宽度

private int mHeight;//容器的高度

private TextView buttonText;

private FrameLayout mButton;

public flippedButton(Context context){

super(context);

this.mContext = context;

init(context);

}

public flippedButton(Context context, AttributeSet attrs) {

super(context, attrs);

this.mContext = context;

init(context);

}

public flippedButton(Context context, AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

this.mContext = context;

init(context);

}

private void init(Context context){

//使用xml中的布局

LayoutInflater.from(context).inflate(R.layout.filpped_button,this, true);

mButton=findViewById(R.id.mButton);

buttonText=findViewById(R.id.buttonText);

}

//测量子View

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

measureChildren(widthMeasureSpec, heightMeasureSpec);

mWidth = getMeasuredWidth();

mHeight = getMeasuredHeight();

//遍历子元件

// int childCount = this.getChildCount();

// for (int i = 0; i

// View child = this.getChildAt(i);

// this.measureChild(child, widthMeasureSpec, heightMeasureSpec);

// int cw = child.getMeasuredWidth();

// int ch = child.getMeasuredHeight();

// }

}

//排列子View的位置

@Override

protected void onLayout(boolean changed, int l, int t, int r, int b) {

int childTop = 0;

for (int i = 0; i

View child = getChildAt(i);

if (child.getVisibility() != GONE) {

child.layout(0, childTop,child.getMeasuredWidth(), childTop + child.getMeasuredHeight());

childTop = childTop + child.getMeasuredHeight();

}

}

}

}

3.在Activity的布局中直接使用

xmlns:android="http://schemas.android.com/apk/res/android"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_gravity="center"

android:orientation="vertical">

android:id="@+id/flippedButton"

android:layout_width="wrap_content"

android:layout_height="wrap_content">

现在可以看到一个最基本的自定义控件已经可以使用了。

二.接下来是重点,控件真正“自定义”的部分。

1.添加自定义事件

a.先定义自定义事件接口

/**

* 定义接口

*/

public interface IMyClick{

public void onMyClick(String str);

}

/**

* 初始化接口变量

*/

IMyClick iMyClick=null;

/**

* 自定义事件监听

* @param _iMyClick

*/

public void setOnMyClickListener(IMyClick _iMyClick){

iMyClick=_iMyClick;

}

b.添加按钮点击事件的监听并调用接口传参

mButton.setOnClickListener(new OnClickListener() {

@Override

public void onClick(View v) {

iMyClick.onMyClick("clicked me");

flipMe();

}

});

c.父级Activity监听事件

fButton=(flippedButton) findViewById(R.id.flippedButton);

fButton.setOnMyClickListener(new flippedButton.IMyClick(){

@Override

public void onMyClick(String str) {

Log.d(LOG_TAG,str);

}

});

2.绘制按钮翻转的动画

这里的3d变换需要用到Camera(android.graphics.Camera)、Matrix。

这里可以想象成用Camera拍摄原件的图形,并将拍摄得到的bitmap传入matrix再绘制到Canvas。

而改变Camera镜头角度就可以得到缩放变形后的图像以实现3d效果。

参考官方demo里的这个工具类的范例Rotate3dAnimation.java(其实是照搬)

a.先建一个3d变换的工具类:

package net.codepig.customviewdemo.model;

import android.graphics.Camera;//注意使用的是graphics里的而不是hardware里的

import android.view.animation.Animation;

import android.view.animation.Transformation;

import android.graphics.Matrix;

/**

* An animation that rotates the view on the Y axis between two specified angles.

* This animation also adds a translation on the Z axis (depth) to improve the effect.

*/

public class Rotate3dAnimation extends Animation {

private final float mFromDegrees;

private final float mToDegrees;

private final float mCenterX;

private final float mCenterY;

private final float mDepthZ;

private final boolean mReverse;

private Camera mCamera;

/**

* Creates a new 3D rotation on the Y axis. The rotation is defined by its

* start angle and its end angle. Both angles are in degrees. The rotation

* is performed around a center point on the 2D space, definied by a pair

* of X and Y coordinates, called centerX and centerY. When the animation

* starts, a translation on the Z axis (depth) is performed. The length

* of the translation can be specified, as well as whether the translation

* should be reversed in time.

*

* @param fromDegrees the start angle of the 3D rotation

* @param toDegrees the end angle of the 3D rotation

* @param centerX the X center of the 3D rotation

* @param centerY the Y center of the 3D rotation

* @param reverse true if the translation should be reversed, false otherwise

*/

public Rotate3dAnimation(float fromDegrees, float toDegrees, float centerX, float centerY, float depthZ, boolean reverse) {

mFromDegrees = fromDegrees;

mToDegrees = toDegrees;

mCenterX = centerX;

mCenterY = centerY;

mDepthZ = depthZ;

mReverse = reverse;

}

@Override

public void initialize(int width, int height, int parentWidth, int parentHeight) {

super.initialize(width, height, parentWidth, parentHeight);

mCamera = new Camera();

}

/**

*

* @param interpolatedTime 动画时间点,类似百分比

* @param t

*/

@Override

protected void applyTransformation(float interpolatedTime, Transformation t) {

final float fromDegrees = mFromDegrees;

float degrees = fromDegrees + ((mToDegrees - fromDegrees) * interpolatedTime);

final float centerX = mCenterX;

final float centerY = mCenterY;

final Camera camera = mCamera;

final Matrix matrix = t.getMatrix();

camera.save();

if (mReverse) {//远离

camera.translate(0.0f, 0.0f, mDepthZ * interpolatedTime);

} else {//靠近

camera.translate(0.0f, 0.0f, mDepthZ * (1.0f - interpolatedTime));

}

camera.rotateY(degrees);

camera.getMatrix(matrix);

camera.restore();

//移动旋转中心到布局中心

matrix.preTranslate(-centerX, -centerY);

matrix.postTranslate(centerX, centerY);

}

}

注意:使用的是graphics里的Camera而不是hardware里的

注意:其中的centerX和centerY是中心点位置。由于Camera的变换是以(0,0)点为原点,所以需要进行变换。

b.调用这个Animation

final Rotate3dAnimation animation = new Rotate3dAnimation(0, 180,centerX, centerY, 0, true);

animation.setDuration(500);//动画持续时间,默认为0

animation.setFillAfter(true);//这个false的话动画完了会复原

mButton.startAnimation(animation);

嗯,这样按钮就翻转了。

3.接下来做出按钮切换的效果

这里有两种方法。可以使用两个按钮一起翻转,也可以一个按钮翻90后改变样式再翻回来。

我这里使用一个按钮的方案。

先设置两种状态的动画。(注意在onMeasure后设置,不然中心位置定位到0,0了)

animationF = new Rotate3dAnimation(0, 90,centerX, centerY, 0, true);

animationF.setDuration(500);//动画持续时间,默认为0

animationF.setFillAfter(true);//这个false的话动画完了会复原

animationB = new Rotate3dAnimation(-90, 0,centerX, centerY, 0, true);

animationB.setDuration(500);

animationB.setFillAfter(true);

给0-90度翻转的动画增加监听,动画完成时根据状态标识改变样式和文字,然后再从-90-0度翻转的动画。

animationF.setAnimationListener(new Animation.AnimationListener() {

@Override

public void onAnimationStart(Animation animation) {

}

@Override

public void onAnimationEnd(Animation animation) {

if (!showBack) {

buttonText.setText("BACK BUTTON");

mButton.setBackgroundColor(getResources().getColor(R.color.colorAccent));

} else { // 背面朝上

buttonText.setText("FRONT BUTTON");

mButton.setBackgroundColor(getResources().getColor(R.color.colorPrimary));

}

mButton.startAnimation(animationB);

}

@Override

public void onAnimationRepeat(Animation animation) {

}

});

三.一个问题:显示不全

翻转的时候发现3d变换扩大了的部分超过了空间原先的显示区域而没有显示出来。

这里涉及到margin和padding的处理。

先给mButton的布局增加margin。

xmlns:android="http://schemas.android.com/apk/res/android"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:orientation="vertical">

android:id="@+id/mButton"

android:layout_margin="100dp"

android:background="@color/colorPrimary"

android:padding="5dp"

android:layout_width="wrap_content"

android:layout_height="wrap_content">

android:id="@+id/buttonText"

android:text="FRONT BUTTON"

android:gravity="center"

android:textColor="@android:color/white"

android:layout_width="100dp"

android:layout_height="50dp" />

在onMeasure处理自定义view的margin和padding。

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

measureChildren(widthMeasureSpec, heightMeasureSpec);

centerX=mButton.getMeasuredWidth()/ 2;

centerY=mButton.getMeasuredHeight() / 2;

mWidth = 0;

mHeight = 0;

//margin

marginLeft = 0;

marginTop = 0;

marginRight = 0;

marginBottom = 0;

//padding

paddingLeft = getPaddingLeft();

paddingTop = getPaddingTop();

paddingRight = getPaddingRight();

paddingBottom = getPaddingBottom();

int childCount = getChildCount();

for (int i = 0; i

View childView = getChildAt(i);

MarginLayoutParams lp = (MarginLayoutParams) childView.getLayoutParams();

measureChild(childView, widthMeasureSpec, heightMeasureSpec);

viewsHeight += childView.getMeasuredHeight();

viewsWidth = Math.max(viewsWidth, childView.getMeasuredWidth());

marginLeft = Math.max(0,lp.leftMargin);//最大左边距

marginTop += lp.topMargin;//上边距之和

marginRight = Math.max(0,lp.rightMargin);//最大右边距

marginBottom += lp.bottomMargin;//下边距之和

}

mWidth = getMeasuredWidth() + paddingLeft + paddingRight + marginLeft + marginRight;

mHeight = getMeasuredHeight() + paddingBottom + paddingTop + marginTop + marginBottom;

setMeasuredDimension(measureWidth(widthMeasureSpec, mWidth), measureHeight(heightMeasureSpec, mHeight));

//动画

animationF = new Rotate3dAnimation(0, 90,centerX, centerY, 0, true);

animationF.setDuration(500);//动画持续时间,默认为0

animationF.setFillAfter(true);//这个false的话动画完了会复原

animationB = new Rotate3dAnimation(-90, 0,centerX, centerY, 0, true);

animationB.setDuration(500);

animationB.setFillAfter(true);

animationF.setAnimationListener(new Animation.AnimationListener() {

@Override

public void onAnimationStart(Animation animation) {

}

@Override

public void onAnimationEnd(Animation animation) {

if (showBack) {

buttonText.setText("BACK BUTTON");

mButton.setBackgroundColor(getResources().getColor(R.color.colorAccent));

} else { // 背面朝上

buttonText.setText("FRONT BUTTON");

mButton.setBackgroundColor(getResources().getColor(R.color.colorPrimary));

}

mButton.startAnimation(animationB);

}

@Override

public void onAnimationRepeat(Animation animation) {

}

});

}

相关github项目地址:flippedButton

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。



推荐阅读
author-avatar
灯火阑珊2502936477
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有