欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android自定义View实现水波纹引导动画

程序员文章站 2024-02-16 23:32:22
一、实现效果图 关于贝塞尔曲线 二、实现代码 1.自定义view package com.czhappy.showintroduce.view...

一、实现效果图

Android自定义View实现水波纹引导动画

关于贝塞尔曲线

Android自定义View实现水波纹引导动画

二、实现代码

1.自定义view

package com.czhappy.showintroduce.view;

import android.content.context;
import android.graphics.bitmap;
import android.graphics.canvas;
import android.graphics.color;
import android.graphics.paint;
import android.graphics.path;
import android.util.attributeset;
import android.view.view;
import android.widget.relativelayout;

/**
 * description: 水波纹动画引导view
 * user: chenzheng
 * date: 2017/1/14 0014
 * time: 18:01
 */
public class rippleintroview extends relativelayout implements runnable {

 private int mmaxradius = 70;
 private int minterval = 20;
 private int count = 0;

 private bitmap mcachebitmap;
 private paint mripplepaint;
 private paint mcirclepaint;
 private path marcpath;

 public rippleintroview(context context) {
  this(context, null);
 }

 public rippleintroview(context context, attributeset attrs) {
  this(context, attrs, 0);
 }

 public rippleintroview(context context, attributeset attrs, int defstyleattr) {
  super(context, attrs, defstyleattr);
  init();
 }

 private void init() {
  mripplepaint = new paint();
  mripplepaint.setantialias(true);
  mripplepaint.setstyle(paint.style.stroke);
  mripplepaint.setcolor(color.white);
  mripplepaint.setstrokewidth(2.f);

  mcirclepaint = new paint();
  mcirclepaint.setantialias(true);
  mcirclepaint.setstyle(paint.style.fill);
  mcirclepaint.setcolor(color.white);

  marcpath = new path();
 }

 /**
  * view大小变化时系统调用
  * @param w
  * @param h
  * @param oldw
  * @param oldh
  */
 @override
 protected void onsizechanged(int w, int h, int oldw, int oldh) {
  super.onsizechanged(w, h, oldw, oldh);
  if (mcachebitmap != null) {
   mcachebitmap.recycle();
   mcachebitmap = null;
  }
 }

 @override
 protected void ondraw(canvas canvas) {
  //获取加号图片view
  view mpluschild = getchildat(0);
  //获取提示图片view
  view mrefschild = getchildat(1);
  if (mpluschild == null || mrefschild == null) return;

  //获取加号图片大小
  final int pw = mpluschild.getwidth();
  final int ph = mpluschild.getheight();

  //获取提示图片大小
  final int fw = mrefschild.getwidth();
  final int fh = mrefschild.getheight();

  if (pw == 0 || ph == 0) return;

  //加号图片中心点坐标
  final float px = mpluschild.getx() + pw / 2;
  final float py = mpluschild.gety() + ph / 2;
  //提示图片左上角坐标
  final float fx = mrefschild.getx();
  final float fy = mrefschild.gety();

  final int rw = pw / 2;
  final int rh = ph / 2;

  if (mcachebitmap == null) {
   mcachebitmap = bitmap.createbitmap(getwidth(), getheight(), bitmap.config.argb_8888);
   canvas cv = new canvas(mcachebitmap);
   super.ondraw(cv);

   //清空所有已经画过的path至原始状态
   marcpath.reset();

   //起始轮廓点移至x,y坐标点,即加号图片正下方再往下20位置
   marcpath.moveto(px, py + rh + minterval);
   //设置二次贝塞尔,实现平滑曲线,前两个参数为操作点坐标,后两个参数为结束点坐标
   marcpath.quadto(px, fy - minterval, fx + fw * 0.618f, fy - minterval);
   //0~255,数值越小越透明
   mripplepaint.setalpha(255);
   cv.drawpath(marcpath, mripplepaint);
   //绘制半径为6的实心圆点
   cv.drawcircle(px, py + rh + minterval, 6, mcirclepaint);
  }

  //绘制背景图片
  canvas.drawbitmap(mcachebitmap, 0, 0, mcirclepaint);

  //保存画布当前的状态
  int save = canvas.save();
  for (int step = count; step <= mmaxradius; step += minterval) {
   //step越大越靠外就越透明
   mripplepaint.setalpha(255 * (mmaxradius - step) / mmaxradius);
   canvas.drawcircle(px, py, (float) (rw + step), mripplepaint);
  }
  //恢复canvas的状态
  canvas.restoretocount(save);
  //延迟80毫秒后开始运行
  postdelayed(this, 80);
 }

 @override
 public void run() {
  //把run对象的引用从队列里拿出来,这样,他就不会执行了,但 run 没有销毁
  removecallbacks(this);
  count += 2;
  count %= minterval;
  invalidate();//重绘
 }

 /**
  * 销毁view时调用,收尾工作
  */
 @override
 protected void ondetachedfromwindow() {
  super.ondetachedfromwindow();
  if (mcachebitmap != null) {
   mcachebitmap.recycle();
   mcachebitmap = null;
  }
 }
}

2.mainactivity.java

package com.czhappy.showintroduce.activity;

import android.os.bundle;
import android.support.v7.app.appcompatactivity;
import android.view.view;
import android.view.viewgroup;

import com.czhappy.showintroduce.r;

public class mainactivity extends appcompatactivity {

 @override
 protected void oncreate(bundle savedinstancestate) {
  super.oncreate(savedinstancestate);
  setcontentview(r.layout.activity_main);

  view view = findviewbyid(r.id.layout_ripple);
  view.setonclicklistener(new view.onclicklistener() {
   @override
   public void onclick(view v) {
    ((viewgroup) v.getparent()).removeview(v);
   }
  });
 }
}

3.activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<framelayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="match_parent"
 android:layout_height="match_parent">

 <textview
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:text="hello world!" />

 <com.czhappy.showintroduce.view.rippleintroview
  android:id="@+id/layout_ripple"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:clickable="true"
  android:fitssystemwindows="true"
  android:background="#aa000000">

  <imageview
   android:id="@+id/iv_plus"
   android:layout_margintop="36dp"
   android:src="@mipmap/ic_add"
   android:layout_alignparentright="true"
   android:layout_marginright="6dp"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"/>

  <imageview
   android:src="@mipmap/tips_subscribe"
   android:id="@+id/tv_title"
   android:layout_below="@id/iv_plus"
   android:layout_margintop="50dp"
   android:layout_alignparentright="true"
   android:layout_marginright="40dp"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"/>

 </com.czhappy.showintroduce.view.rippleintroview>

</framelayout>

三、源码下载

http://xiazai.jb51.net/201701/yuanma/androidshowintroduce(jb51.net).rar

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