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

简介: 自定义view渐变背景,同时监听手势自动生成小圆球。   宿主Activity如下:   package com.edaixi.tempbak; import java.util.ArrayList; import android.

自定义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>

  

 

目录
相关文章
|
27天前
|
Android开发 开发者
安卓应用开发中的自定义视图
【9月更文挑战第37天】在安卓开发的海洋中,自定义视图犹如一座座小岛,等待着勇敢的探索者去发现其独特之处。本文将带领你踏上这段旅程,从浅滩走向深海,逐步揭开自定义视图的神秘面纱。
31 3
|
20天前
|
数据可视化 Android开发 开发者
安卓应用开发中的自定义View组件
【10月更文挑战第5天】在安卓应用开发中,自定义View组件是提升用户交互体验的利器。本篇将深入探讨如何从零开始创建自定义View,包括设计理念、实现步骤以及性能优化技巧,帮助开发者打造流畅且富有创意的用户界面。
51 0
|
4天前
|
缓存 数据处理 Android开发
在 Android 中使用 RxJava 更新 View
【10月更文挑战第20天】使用 RxJava 来更新 View 可以提供更优雅、更高效的解决方案。通过合理地运用操作符和订阅机制,我们能够轻松地处理异步数据并在主线程中进行 View 的更新。在实际应用中,需要根据具体情况进行灵活运用,并注意相关的注意事项和性能优化,以确保应用的稳定性和流畅性。可以通过不断的实践和探索,进一步掌握在 Android 中使用 RxJava 更新 View 的技巧和方法,为开发高质量的 Android 应用提供有力支持。
|
4天前
|
缓存 调度 Android开发
Android 在子线程更新 View
【10月更文挑战第21天】在 Android 开发中,虽然不能直接在子线程更新 View,但通过使用 Handler、AsyncTask 或 RxJava 等方法,可以实现子线程操作并在主线程更新 View 的目的。在实际应用中,需要根据具体情况选择合适的方法,并注意相关的注意事项和性能优化,以确保应用的稳定性和流畅性。可以通过不断的实践和探索,进一步掌握在子线程更新 View 的技巧和方法,为开发高质量的 Android 应用提供支持。
8 2
|
5天前
|
XML 前端开发 Android开发
Android面试高频知识点(3) 详解Android View的绘制流程
Android面试高频知识点(3) 详解Android View的绘制流程
Android面试高频知识点(3) 详解Android View的绘制流程
|
9天前
|
XML 前端开发 Android开发
Android面试高频知识点(3) 详解Android View的绘制流程
Android面试高频知识点(3) 详解Android View的绘制流程
15 2
|
21天前
|
XML 前端开发 Android开发
Android View的绘制流程和原理详细解说
Android View的绘制流程和原理详细解说
29 3
|
20天前
|
XML 前端开发 Java
安卓应用开发中的自定义View组件
【10月更文挑战第5天】自定义View是安卓应用开发的一块基石,它为开发者提供了无限的可能。通过掌握其原理和实现方法,可以创造出既美观又实用的用户界面。本文将引导你了解自定义View的创建过程,包括绘制技巧、事件处理以及性能优化等关键步骤。
|
2月前
|
Android开发 开发者
安卓开发中的自定义视图:从入门到精通
【9月更文挑战第19天】在安卓开发的广阔天地中,自定义视图是一块充满魔力的土地。它不仅仅是代码的堆砌,更是艺术与科技的完美结合。通过掌握自定义视图,开发者能够打破常规,创造出独一无二的用户界面。本文将带你走进自定义视图的世界,从基础概念到实战应用,一步步展示如何用代码绘出心中的蓝图。无论你是初学者还是有经验的开发者,这篇文章都将为你打开一扇通往创意和效率的大门。让我们一起探索自定义视图的秘密,将你的应用打造成一件艺术品吧!
56 10
|
2月前
|
XML 编解码 Android开发
安卓开发中的自定义视图控件
【9月更文挑战第14天】在安卓开发中,自定义视图控件是一种高级技巧,它可以让开发者根据项目需求创建出独特的用户界面元素。本文将通过一个简单示例,引导你了解如何在安卓项目中实现自定义视图控件,包括创建自定义控件类、处理绘制逻辑以及响应用户交互。无论你是初学者还是有经验的开发者,这篇文章都会为你提供有价值的见解和技巧。
38 3