利用SurfaceView实现下雨与下雪动画效果详解(Kotlin语法)

2019-10-12 编辑:admin 来源:互联网 阅读次数:
  导读: 前言 最近打算做一波东西巩固一下自己近期所学所得。话不多说,先看一下最终完成的效果图: 下雨.gif 这里比较懒……第二个图片中还是降雨……不过这不是关键点…… 下雪.gif 录制的mp4,转成了...

前言

最近打算做一波东西巩固一下自己近期所学所得。话不多说,先看一下最终完成的效果图:


下雨.gif

这里比较懒……第二个图片中还是降雨……不过这不是关键点……

下雪.gif

录制的mp4,转成了gif。第一个gif设置了帧率,所以看起来可能掉帧比较严重,但是实际上并不会,因为这里我也注意了1s要绘制60帧的问题。阅读本文需要一些基本的View知识和会一些基础Kotlin语法。说实话,就知识点来说,跟Kotlin是没多大关系的,只要懂基本的语法就可以了。

理清思路

在动手前先要理一下思路,从以下几个方面来分析一下该采用什么方案来实现这个效果:

工作线程:首先要想到的是:这个下雨的效果需要通过不停的绘制来实现,如果在主线程做这个操作,很有可能会阻塞主线程,导致ANR或者异常卡顿。所以需要一个能在子线程进行绘制的View,毫无疑问SurfaceView可以满足这个需求。 如何实现:分析一下一颗雨滴的实现。首先,简单的效果其实可以用画线的方式代替。并不是每个人都有写轮眼,动态视力那么好的,一旦动起来谁还知道他是条线还是雨滴……当然了,Canvas绘制的API有很多,并不一定非要用这种方式来实现。所以在在设计类的时候我们将draw的方法设置成可以让子类复写就可以了,你不满意我的实现?没问题,我给你改的自由~ 下落的实现:让雨滴动起来,有两种方式,一种是纯按坐标来绘制,另外一种是利用属性动画,自己重写估值器,动态改变y值。最终我还是采用了前一种方案,后一种属性动画的方案我为什么放弃了呢?原因是:这里的绘制的方式是靠外部不断的触发绘制事件来实现动态绘制的,很显然第一种方式更加符合这里的情况。

以上就是我初期的一些关于实现的思考了,接下来是代码实现分析。

代码实现分析

先放代码结构图:

代码结构

WeatherShape所有天气的父类,Rain和Snow是两个具体实现类。

看一下父类的代码:

package com.xiasuhuei321.gank_kotlin.customview.weather

import android.graphics.Canvas
import android.graphics.Paint
import android.graphics.PointF
import com.xiasuhuei321.gank_kotlin.context
import com.xiasuhuei321.gank_kotlin.extension.getScreenWidth
import java.util.*

/**
 * Created by xiasuhuei321 on 2017/9/5.
 * author:luo
 * e-mail:xiasuhuei321@163.com
 *
 * desc: All shape"s parent class.It describes a shape will have
 * what feature.It"s draw flows are:
 * 1.Outside the class init some value such as the start and the
 * end point.
 * 2.Invoke draw(Canvas) method, in this method, there are still
 * two flows:
 * 1) Get random value to init paint, this will affect the shape
 * draw style.
 * 2) When the shape is not used, invoke init method, and when it
 * is not used invoke drawWhenInUse(Canvas) method. It should be
 * override by user and to implement draw itself.
 *
 */
abstract class WeatherShape(val start: PointF, val end: PointF) {
 open var TAG = "WeatherShape"

 /**
  * 是否是正在被使用的状态
  */
 var isInUse = false

 /**
  * 是否是随机刷新的Shape
  */
 var isRandom = false

 /**
  * 下落的速度,特指垂直方向,子类可以实现自己水平方向的速度
  */
 var speed = 0.05f

 /**
  * shape的宽度
  */
 var width = 5f

 var shapeAlpha = 100

 var paint = Paint().apply {
  strokeWidth = width
  isAntiAlias = true
  alpha = alpha
 }

 // 总共下落的时间
 var lastTime = 0L
 // 原始x坐标位置
 var originX = 0f

 /**
  * 根据自己的规则计算加速度,如果是匀速直接 return 0
  */
 abstract fun getAcceleration(): Float

 /**
  * 绘制自身,这里在Shape是非使用的时候进行一些初始化操作
  */
 open fun draw(canvas: Canvas) {
  if (!isInUse) {
   lastTime += randomPre()
   initStyle()
   isInUse = true
  } else {
   drawWhenInUse(canvas)
  }
 }

 /**
  * Shape在使用的时候调用此方法
  */
 abstract fun drawWhenInUse(canvas: Canvas)

 /**
  * 初始化Shape风格
  */
 open fun initStyle() {
  val random = Random()
  // 获取随机透明度
  shapeAlpha = random.nextInt(155) + 50
  // 获得起点x偏移
  val translateX = random.nextInt(10).toFloat() + 5
  if (!isRandom) {
   start.x = translateX + originX
   end.x = translateX + originX
  } else {
   // 如果是随机Shape,将x坐标随机范围扩大到整个屏幕的宽度
   val randomWidth = random.nextInt(context.getScreenWidth())
   start.x = randomWidth.toFloat()
   end.x = randomWidth.toFloat()
  }
  speed = randomSpeed(random)
  // 初始化length的工作留给之后对应的子类去实现
  // 初始化color也留给子类去实现
  paint.apply {
   alpha = shapeAlpha
   strokeWidth = width
   isAntiAlias = true
  }
  // 如果有什么想要做的,刚好可以在追加上完成,就使用这个函数
  wtc(random)
 }

 /**
  * Empty body, this will be invoke in initStyle
  * method.If current initStyle method can satisfy your need
  * but you still add something, by override this method
  * will be a good idea to solve the problem.
  */
 open fun wtc(random:Random): Unit {

 }

 abstract fun randomSpeed(random: Random): Float

 /**
  * 获取一个随机的提前量,让shape在竖屏上有一个初始的偏移
  */
 open fun randomPre(): Long {
  val random = Random()
  val pre = random.nextInt(1000).toLong()
  return pre
 }
}


本文关键词:

文章出自:互联网,文中内容和观点不代表本网站立场,如有侵权,请您告知,我们将及时处理。

 
 
科技头条 - 关注科技最新动态,上科技头条的才是真的头条 - 惟翔资讯
科技头条 关注科技最新动态,上科技头条的才是真的头条 服务QQ:175529508 e-mail:zk8312@163.com
Copyright @ 科技头条 2014 All Rights Reserved | 吉ICP备14005127号-2
本站部分资源来自网友上传,如果无意之中侵犯了您的版权,请联系本站,本站将在3个工作日内删除。