热门标签 | 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开发实现的计时器功能示例
    本文分享了Android开发实现的计时器功能示例,包括效果图、布局和按钮的使用。通过使用Chronometer控件,可以实现计时器功能。该示例适用于Android平台,供开发者参考。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • 本文介绍了使用kotlin实现动画效果的方法,包括上下移动、放大缩小、旋转等功能。通过代码示例演示了如何使用ObjectAnimator和AnimatorSet来实现动画效果,并提供了实现抖动效果的代码。同时还介绍了如何使用translationY和translationX来实现上下和左右移动的效果。最后还提供了一个anim_small.xml文件的代码示例,可以用来实现放大缩小的效果。 ... [详细]
  • 在Xamarin XAML语言中如何在页面级别构建ControlTemplate控件模板
    本文介绍了在Xamarin XAML语言中如何在页面级别构建ControlTemplate控件模板的方法和步骤,包括将ResourceDictionary添加到页面中以及在ResourceDictionary中实现模板的构建。通过本文的阅读,读者可以了解到在Xamarin XAML语言中构建控件模板的具体操作步骤和语法形式。 ... [详细]
  • Activiti7流程定义开发笔记
    本文介绍了Activiti7流程定义的开发笔记,包括流程定义的概念、使用activiti-explorer和activiti-eclipse-designer进行建模的方式,以及生成流程图的方法。还介绍了流程定义部署的概念和步骤,包括将bpmn和png文件添加部署到activiti数据库中的方法,以及使用ZIP包进行部署的方式。同时还提到了activiti.cfg.xml文件的作用。 ... [详细]
  • 开发笔记:(002)spring容器中bean初始化销毁时执行的方法及其3种实现方式
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了(002)spring容器中bean初始化销毁时执行的方法及其3种实现方式相关的知识,希望对你有一定的参考价值。 ... [详细]
  • 在一对一直播源码使用过程中,有时会出现软键盘切换闪屏问题,就是当切换表情的时候屏幕会跳动,因此要对一对一直播源码表情面板无缝切换进行优化。 ... [详细]
  • Spring源码解密之默认标签的解析方式分析
    本文分析了Spring源码解密中默认标签的解析方式。通过对命名空间的判断,区分默认命名空间和自定义命名空间,并采用不同的解析方式。其中,bean标签的解析最为复杂和重要。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • 自动轮播,反转播放的ViewPagerAdapter的使用方法和效果展示
    本文介绍了如何使用自动轮播、反转播放的ViewPagerAdapter,并展示了其效果。该ViewPagerAdapter支持无限循环、触摸暂停、切换缩放等功能。同时提供了使用GIF.gif的示例和github地址。通过LoopFragmentPagerAdapter类的getActualCount、getActualItem和getActualPagerTitle方法可以实现自定义的循环效果和标题展示。 ... [详细]
  • 本文详细介绍了MySQL表分区的创建、增加和删除方法,包括查看分区数据量和全库数据量的方法。欢迎大家阅读并给予点评。 ... [详细]
  • Oracle seg,V$TEMPSEG_USAGE与Oracle排序的关系及使用方法
    本文介绍了Oracle seg,V$TEMPSEG_USAGE与Oracle排序之间的关系,V$TEMPSEG_USAGE是V_$SORT_USAGE的同义词,通过查询dba_objects和dba_synonyms视图可以了解到它们的详细信息。同时,还探讨了V$TEMPSEG_USAGE的使用方法。 ... [详细]
  • Flutter 布局(四) Baseline、FractionallySizedBox、IntrinsicHeight、IntrinsicWidth详解
    本文主要介绍Flutter布局中的Baseline、FractionallySizedBox、IntrinsicHeight、IntrinsicWidth四种控件,详细介绍了其布局 ... [详细]
  • 本文整理了Java中org.apache.pig.backend.executionengine.ExecException.<init>()方法的一些代码 ... [详细]
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社区 版权所有