Android 用属性动画自定义view的渐变背景

自定义view渐变背景,同时监听手势自动生成小圆球。

 

宿主Activity如下:

 

package com.edaixi.tempbak;

import java.util.ArrayList;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ArgbEvaluator;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RadialGradient;
import android.graphics.Shader;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.OvalShape;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.view.Window;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.widget.LinearLayout;

@SuppressLint("NewApi")
public class MainActivity extends Activity {

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		setContentView(R.layout.activity_main);
		LinearLayout container = (LinearLayout) findViewById(R.id.container);
		container.addView(new MyAnimationView(this));
	}

	public class MyAnimationView extends View {

		private static final int RED = 0xffFF8080;
		private static final int BLUE = 0xff8080FF;
		private static final int CYAN = 0xff80ffff;
		private static final int GREEN = 0xff80ff80;

		public final ArrayList<ShapeHolder> balls = new ArrayList<ShapeHolder>();
		AnimatorSet animation = null;

		public MyAnimationView(Context context) {
			super(context);
			/**************************************************************************************************
			 *
			 * 设置自定义view的背景,是一个渐变的过程,用ValueAnimator实现,ValueAnimator是Property
			 * Animation系统 的核心类,它包含了配置Property Animation属性的大部分方法,那要实现一个Property
			 * Animation,都需要直接 或间接使用ValueAnimator类,使用ValueAnimator的步骤如下:
			 * 1.调用ValueAnimation类中的ofInt(int...values)、ofFloat(String
			 * propertyName,float...values)等静态方
			 * 法实例化ValueAnimator对象,并设置目标属性的属性名、初始值或结束值等值;
			 * 2.调用addUpdateListener(AnimatorUpdateListener
			 * mListener)方法为ValueAnimator对象设置属性变化的监听器
			 * 3.创建自定义的Interpolator,调用setInterpolator(TimeInterpolator
			 * value)为ValueAniamtor设置自定义的 Interpolator;(可选,不设置默认为缺省值)
			 * 4.创建自定义的TypeEvaluator,调用setEvaluator(TypeEvaluator
			 * value)为ValueAnimator设置自定义的 TypeEvaluator;(可选,不设置默认为缺省值)
			 * 5.在AnimatorUpdateListener 中的实现方法为目标对象的属性设置计算好的属性值。
			 * 6.设置动画的持续时间、是否重复及重复次数等属性; 7.为ValueAnimator设置目标对象并开始执行动画。
			 *
			 * *****************************************************************
			 */
			ValueAnimator colorAnim = ObjectAnimator.ofInt(this,
					"backgroundColor", RED, BLUE);
			colorAnim.setDuration(3000);
			colorAnim.setEvaluator(new ArgbEvaluator());
			colorAnim.setRepeatCount(ValueAnimator.INFINITE);
			colorAnim.setRepeatMode(ValueAnimator.REVERSE);
			colorAnim.start();
		}

		@SuppressLint("NewApi")
		@Override
		public boolean onTouchEvent(MotionEvent event) {
			if (event.getAction() != MotionEvent.ACTION_DOWN
					&& event.getAction() != MotionEvent.ACTION_MOVE) {
				return false;
			}
			ShapeHolder newBall = addBall(event.getX(), event.getY());

			/** Bouncing animation with squash and stretch **/
			float startY = newBall.getY();
			float endY = getHeight() - 50f;
			float h = (float) getHeight();
			float eventY = event.getY();
			int duration = (int) (500 * ((h - eventY) / h));
			ValueAnimator bounceAnim = ObjectAnimator.ofFloat(newBall, "y",
					startY, endY);
			bounceAnim.setDuration(duration);
			bounceAnim.setInterpolator(new AccelerateInterpolator());
			ValueAnimator squashAnim1 = ObjectAnimator.ofFloat(newBall, "x",
					newBall.getX(), newBall.getX() - 25f);
			squashAnim1.setDuration(duration / 4);
			squashAnim1.setRepeatCount(1);
			squashAnim1.setRepeatMode(ValueAnimator.REVERSE);
			squashAnim1.setInterpolator(new DecelerateInterpolator());
			ValueAnimator squashAnim2 = ObjectAnimator.ofFloat(newBall,
					"width", newBall.getWidth(), newBall.getWidth() + 50);
			squashAnim2.setDuration(duration / 4);
			squashAnim2.setRepeatCount(1);
			squashAnim2.setRepeatMode(ValueAnimator.REVERSE);
			squashAnim2.setInterpolator(new DecelerateInterpolator());
			ValueAnimator stretchAnim1 = ObjectAnimator.ofFloat(newBall, "y",
					endY, endY + 25f);
			stretchAnim1.setDuration(duration / 4);
			stretchAnim1.setRepeatCount(1);
			stretchAnim1.setInterpolator(new DecelerateInterpolator());
			stretchAnim1.setRepeatMode(ValueAnimator.REVERSE);
			ValueAnimator stretchAnim2 = ObjectAnimator.ofFloat(newBall,
					"height", newBall.getHeight(), newBall.getHeight() - 25);
			stretchAnim2.setDuration(duration / 4);
			stretchAnim2.setRepeatCount(1);
			stretchAnim2.setInterpolator(new DecelerateInterpolator());
			stretchAnim2.setRepeatMode(ValueAnimator.REVERSE);
			ValueAnimator bounceBackAnim = ObjectAnimator.ofFloat(newBall, "y",
					endY, startY);
			bounceBackAnim.setDuration(duration);
			bounceBackAnim.setInterpolator(new DecelerateInterpolator());
			// Sequence the down/squash&stretch/up animations
			AnimatorSet bouncer = new AnimatorSet();
			bouncer.play(bounceAnim).before(squashAnim1);
			bouncer.play(squashAnim1).with(squashAnim2);
			bouncer.play(squashAnim1).with(stretchAnim1);
			bouncer.play(squashAnim1).with(stretchAnim2);
			bouncer.play(bounceBackAnim).after(stretchAnim2);

			// Fading animation - remove the ball when the animation is done
			ValueAnimator fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha",
					1f, 0f);
			fadeAnim.setDuration(250);
			fadeAnim.addListener(new AnimatorListenerAdapter() {
				@Override
				public void onAnimationEnd(Animator animation) {
					balls.remove(((ObjectAnimator) animation).getTarget());

				}
			});

			// Sequence the two animations to play one after the other
			AnimatorSet animatorSet = new AnimatorSet();
			animatorSet.play(bouncer).before(fadeAnim);

			// Start the animation
			animatorSet.start();

			return true;
		}

		private ShapeHolder addBall(float x, float y) {
			OvalShape circle = new OvalShape();
			circle.resize(50f, 50f);
			ShapeDrawable drawable = new ShapeDrawable(circle);
			ShapeHolder shapeHolder = new ShapeHolder(drawable);
			shapeHolder.setX(x - 25f);
			shapeHolder.setY(y - 25f);
			int red = (int) (Math.random() * 255);
			int green = (int) (Math.random() * 255);
			int blue = (int) (Math.random() * 255);
			int color = 0xff000000 | red << 16 | green << 8 | blue;
			Paint paint = drawable.getPaint(); // new
												// Paint(Paint.ANTI_ALIAS_FLAG);
			int darkColor = 0xff000000 | red / 4 << 16 | green / 4 << 8 | blue
					/ 4;
			RadialGradient gradient = new RadialGradient(37.5f, 12.5f, 50f,
					color, darkColor, Shader.TileMode.CLAMP);
			paint.setShader(gradient);
			shapeHolder.setPaint(paint);
			balls.add(shapeHolder);
			return shapeHolder;
		}

		@Override
		protected void onDraw(Canvas canvas) {
			for (int i = 0; i < balls.size(); ++i) {
				ShapeHolder shapeHolder = balls.get(i);
				canvas.save();
				canvas.translate(shapeHolder.getX(), shapeHolder.getY());
				shapeHolder.getShape().draw(canvas);
				canvas.restore();
			}
		}
	}

}

  

 

自定义

ShapeHolder 

如下:

 

/*
 * Copyright (C) 2010 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.edaixi.tempbak;

import android.graphics.Paint;
import android.graphics.RadialGradient;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.Shape;

/**
 * A data structure that holds a Shape and various properties that can be used to define
 * how the shape is drawn.
 */
public class ShapeHolder {
    private float x = 0, y = 0;
    private ShapeDrawable shape;
    private int color;
    private RadialGradient gradient;
    private float alpha = 1f;
    private Paint paint;

    public void setPaint(Paint value) {
        paint = value;
    }
    public Paint getPaint() {
        return paint;
    }

    public void setX(float value) {
        x = value;
    }
    public float getX() {
        return x;
    }
    public void setY(float value) {
        y = value;
    }
    public float getY() {
        return y;
    }
    public void setShape(ShapeDrawable value) {
        shape = value;
    }
    public ShapeDrawable getShape() {
        return shape;
    }
    public int getColor() {
        return color;
    }
    public void setColor(int value) {
        shape.getPaint().setColor(value);
        color = value;
    }
    public void setGradient(RadialGradient value) {
        gradient = value;
    }
    public RadialGradient getGradient() {
        return gradient;
    }

    public void setAlpha(float alpha) {
        this.alpha = alpha;
        shape.setAlpha((int)((alpha * 255f) + .5f));
    }

    public float getWidth() {
        return shape.getShape().getWidth();
    }
    public void setWidth(float width) {
        Shape s = shape.getShape();
        s.resize(width, s.getHeight());
    }

    public float getHeight() {
        return shape.getShape().getHeight();
    }
    public void setHeight(float height) {
        Shape s = shape.getShape();
        s.resize(s.getWidth(), height);
    }

    public ShapeHolder(ShapeDrawable s) {
        shape = s;
    }
}

  

自定义Layout布局渐变背景如下:

 

package com.edaixi.tempbak;

import android.animation.ArgbEvaluator;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.RelativeLayout;

@SuppressLint("NewApi")
public class CustomerRelativeLayout extends RelativeLayout {
	private static final int RED = 0xffFF8080;
	private static final int BLUE = 0xff8080FF;

	public CustomerRelativeLayout(Context context) {
		super(context);
		setBg();
	}

	public CustomerRelativeLayout(Context context, AttributeSet attrs,
			int defStyleAttr, int defStyleRes) {
		super(context, attrs, defStyleAttr, defStyleRes);
		setBg();
	}

	public CustomerRelativeLayout(Context context, AttributeSet attrs,
			int defStyleAttr) {
		super(context, attrs, defStyleAttr);
		setBg();
	}

	public CustomerRelativeLayout(Context context, AttributeSet attrs) {
		super(context, attrs);
		setBg();
	}

	public void setBg() {
		ValueAnimator colorAnim = ObjectAnimator.ofInt(this, "backgroundColor",
				RED, BLUE);
		colorAnim.setDuration(3000);
		colorAnim.setEvaluator(new ArgbEvaluator());
		colorAnim.setRepeatCount(ValueAnimator.INFINITE);
		colorAnim.setRepeatMode(ValueAnimator.REVERSE);
		colorAnim.start();
	}
}

  

 

布局中引用即可“

<?xml version="1.0" encoding="utf-8"?>
<com.edaixi.tempbak.CustomerRelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/rl_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

</com.edaixi.tempbak.CustomerRelativeLayout>

  

 

时间: 2024-08-02 04:04:00

Android 用属性动画自定义view的渐变背景的相关文章

Android中属性动画Property Animation使用示例(一)

MainActivity如下: package cc.cn; import android.animation.Animator; import android.animation.AnimatorInflater; import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import andro

Android中属性动画Property Animation使用示例(三)

MainActivity如下: package cc.cn; import android.os.Bundle; import android.view.View; import android.widget.RelativeLayout; import android.animation.AnimatorInflater; import android.animation.ArgbEvaluator; import android.animation.ObjectAnimator; impor

Android 高手进阶之自定义View,自定义属性(带进度的圆形进度条)

很多的时候,系统自带的View满足不了我们功能的需求,那么我们就需要自己来自定义一个能满足我们需求的View,自定义View我们需要先继承View,添加类的构造方法,重写父类View的一些方法,例如onDraw,为了我们自定义的View在一个项目中能够重用,有时候我们需要自定义其属性,举个很简单的例子,我在项目中的多个界面使用我自定义的View,每个界面该自定义View的颜色都不相同,这时候如果没有自定义属性,那我们是不是需要构建不同颜色的View出来呢,这样子我们的代码就会显得很沉厄,所以这时

Android App开发中自定义View和ViewGroup的实例教程_Android

ViewAndroid所有的控件都是View或者View的子类,它其实表示的就是屏幕上的一块矩形区域,用一个Rect来表示,left,top表示View相对于它的parent View的起点,width,height表示View自己的宽高,通过这4个字段就能确定View在屏幕上的位置,确定位置后就可以开始绘制View的内容了. View绘制过程View的绘制可以分为下面三个过程: MeasureView会先做一次测量,算出自己需要占用多大的面积.View的Measure过程给我们暴露了一个接口o

Android中属性动画Property Animation使用示例(四)

MainActivity如下: package cc.cn; import android.animation.AnimatorInflater; import android.animation.IntEvaluator; import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.animation.ValueAnimator.AnimatorUpdateLis

android开妇这自定义View之使用TextPaint使\n等符号生效

同学们现在或以后自定义View画文字的时候,肯定会需要将文字换行,大家都知道\n,那么我们来画试一下: canvas.drawText("这里是测试换行符\n第二行",300,300,mPaint); 如何解决呢?使用TextPaint: private TextPaint mPaint; 实例化方式与Paint一致(本来就是Paint的儿子) 接下来: StaticLayout layout = new StaticLayout("这里是测试换行符\n第二行",

Android自定义view实现阻尼效果的加载动画_Android

效果: 需要知识: 1. 二次贝塞尔曲线 2. 动画知识 3. 基础自定义view知识 先来解释下什么叫阻尼运动 阻尼振动是指,由于振动系统受到摩擦和介质阻力或其他能耗而使振幅随时间逐渐衰减的振动,又称减幅振动.衰减振动.[1] 不论是弹簧振子还是单摆由于外界的摩擦和介质阻力总是存在,在振动过程中要不断克服外界阻力做功,消耗能量,振幅就会逐渐减小,经过一段时间,振动就会完全停下来.这种振幅随时间减小的振动称为阻尼振动.因为振幅与振动的能量有关,阻尼振动也就是能量不断减少的振动.阻尼振动是非简谐运

Android自定义View实现loading动画加载效果

项目开发中对Loading的处理是比较常见的,安卓系统提供的不太美观,引入第三发又太麻烦,这时候自己定义View来实现这个效果,并且进行封装抽取给项目提供统一的loading样式是最好的解决方式了. 先自定义一个View,继承自LinearLayout,在Layout中,添加布局控件 /** * Created by xiedong on 2017/3/7. */ public class Loading_view extends LinearLayout { private Context m

Android自定义View之圆形进度条总结

最近撸了一个圆形进度条的开源项目,算是第一次完完整整的使用自定义 View .在此对项目开发思路做个小结,欢迎大家 Star 和 Fork. 该项目总共实现了三种圆形进度条效果 CircleProgress:圆形进度条,可以实现仿 QQ 健康计步器的效果,支持配置进度条背景色.宽度.起始角度,支持进度条渐变 DialProgress:类似 CircleProgress,但是支持刻度 WaveProgress:实现了水波纹效果的圆形进度条,不支持渐变和起始角度配置,如需此功能可参考 CircleP