热门标签 | 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

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



推荐阅读
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • 拥抱Android Design Support Library新变化(导航视图、悬浮ActionBar)
    转载请注明明桑AndroidAndroid5.0Loollipop作为Android最重要的版本之一,为我们带来了全新的界面风格和设计语言。看起来很受欢迎࿰ ... [详细]
  • 今天就跟大家聊聊有关怎么在Android应用中实现一个换肤功能,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根 ... [详细]
  • Android开发实现的计时器功能示例
    本文分享了Android开发实现的计时器功能示例,包括效果图、布局和按钮的使用。通过使用Chronometer控件,可以实现计时器功能。该示例适用于Android平台,供开发者参考。 ... [详细]
  • android 触屏处理流程,android触摸事件处理流程 ? FOOKWOOD「建议收藏」
    android触屏处理流程,android触摸事件处理流程?FOOKWOOD「建议收藏」最近在工作中,经常需要处理触摸事件,但是有时候会出现一些奇怪的bug,比如有时候会检测不到A ... [详细]
  • android:EditText属性去边框EditText继承关系:View--TextView--EditTextEditText的属性很多,这里介绍几个:android:h ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • 在开发app时,使用了butterknife后,在androidStudio打包apk时可能会遇到报错。为了解决这个问题,可以通过打开proguard-rules.pro文件进行代码混淆来解决。本文介绍了具体的混淆代码和方法。 ... [详细]
  • 闭包一直是Java社区中争论不断的话题,很多语言都支持闭包这个语言特性,闭包定义了一个依赖于外部环境的自由变量的函数,这个函数能够访问外部环境的变量。本文以JavaScript的一个闭包为例,介绍了闭包的定义和特性。 ... [详细]
  • Android源码中的Builder模式及其作用
    本文主要解释了什么是Builder模式以及其作用,并结合Android源码来分析Builder模式的实现。Builder模式是将产品的设计、表示和构建进行分离,通过引入建造者角色,简化了构建复杂产品的流程,并且使得产品的构建可以灵活适应变化。使用Builder模式可以解决开发者需要关注产品表示和构建步骤的问题,并且当构建流程发生变化时,无需修改代码即可适配新的构建流程。 ... [详细]
  • 我收到这个错误.我怎么能在我的情况下解决这个问题?Bitmapcannotberesolvedtoatype发生错误的行publicvoidonPageStart ... [详细]
  • Editedbymythouhttp:www.cnblogs.commythoupublicbooleancreateReflectedForAdapter(){finalintr ... [详细]
  • 篇首语:本文由编程笔记#小编为大家整理,主要介绍了10分钟了解Android的事件分发相关的知识,希望对你有一定的参考价值。什么是事件分发?大家 ... [详细]
  • 当我在doWork方法中运行代码时,通过单击button1,进度条按预期工作.但是,当我从其他方法(即btn2,btn3)将列表传递给doWork方法时,进度条在启动后会跳转到10 ... [详细]
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社区 版权所有