首先是最终实现的效果图:

先分析一下雨滴的实现:

每个雨滴其实就是一条线,通过canvas.drawLine()绘制

线(雨滴)的长度、宽度、下落速度、透明度以及位置都是在一定范围内随机生成

每 draw 一次然后改变雨滴的位置然后重绘即可实现雨滴的下落效果

分析完了,那么可以直接写一个类直接继承 View ,然后重写 onDraw()吗?可以看到效果图中的雨滴的下落速度很快,那么意味着每一帧都要调用 onDraw()一次使其重新绘制一次,假如你的 onDraw() 方法里面的渲染代码稍微有点费时,而 View 的 onDraw()方法调用是在 UI 线程中,那么绘制出来的效果就不会那么流畅,甚至还会阻塞 UI 线程,所以为了更流畅的效果并且不阻塞 UI 线程,我们这里使用 SurfaceView 来实现。

初识 SurfaceView

SurfaceView 直接继承自 View,View 必须在 UI 线程中绘制,而 SurfaceView 不同于 View,它可以在非 UI 线程中绘制并显示在界面上,这意味着你可以自己新开一个线程,然后把绘制渲染的代码放在该线程中。

Surface 是 Z 轴排序的,SurfaceView 的 Z 轴位置小于它的宿主 Window,代表它总是在自己所在 Window 的后面,既然在后面,那么是怎么显示的呢?SurfaceView 在其 Window 中打出一个“孔”(其实就是在其宿主 Window 上设置了一块透明区域来使其能够显示),意味着他的兄弟节点的 View 会覆盖它,例如你可以在 SurfaceView 上方放置按钮,文本等控件。

要想访问下面的 Surface ,可以通过 Android 提供给我们的 SurfaceHolder 接口。可以调用 SurfaceView 的 getHolder()来获取。

SurfaceView 是有生命周期的,我们必须在它生命周期期间进行执行绘制代码,所以我们需要监听 SurfaceView 的状态(例如创建以及销毁),这里 Android 为我们提供了 SurfaceHolder.Callback这个接口来可以让我们方便的监听 SurfaceView 的状态。

那么下面看下 SurfaceHolder.Callback接口

public interface Callback {

// SurfaceView 创建时调用(SurfaceView的窗口可见时)

public void surfaceCreated(SurfaceHolder holder);

// SurfaceView 改变时调用

public void surfaceChanged(SurfaceHolder holder, int format, int width,

int height);

// SurfaceView 销毁时调用(SurfaceView的窗口不可见时)

public void surfaceDestroyed(SurfaceHolder holder);

}

我们的绘制代码需要在 surfaceCreated 和 surfaceDestroyed 之间执行,否则无效,SurfaceHolder.Callback的回调方法是执行在 UI 线程中的,绘制线程需要我们自己手动创建。

View 和 SurfaceView 的使用场景

View 适合那些与用户交互并且渲染时间不是很长的控件,因为 View 的绘制和用户交互都处在 UI 线程中。

SurfaceView 适合迅速的更新界面或者渲染时间比较长以至于影响到用户体验的场景。

使用 SurfaceView(实现)

这里我们和自定义 View 类似,写一个类 DynamicWeatherView 继承自 SurfaceView,然后为了监听 SurfaceView 的状态,所以我们还需要实现 SurfaceHolder.Callback接口来监听 SurfaceView 的状态,接口的回调具体时机上面也已经介绍过了。

public class DynamicWeatherView extends SurfaceView implements SurfaceHolder.Callback{

public DynamicWeatherView(Context context) {

this(context, null);

}

public DynamicWeatherView(Context context, AttributeSet attrs) {

this(context, attrs, 0);

}

public DynamicWeatherView(Context context, AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

}

// SurfaceView 创建时调用(可见)

@Override

public void surfaceCreated(SurfaceHolder holder) {

}

// SurfaceView 销毁时调用(不可见)

@Override

public void surfaceDestroyed(SurfaceHolder holder) {

}

@Override

public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

}

}

上面也提到了,控制 Surface 我们需要 SurfaceHolder 对象,调用 SurfaceView 的getHolder()即可获得,然后为这个 SurfaceHolder 添加一个 SurfaceHolder.Callback回调,这里就是 DynamicWeatherView 当前对象

private SurfaceHolder mHolder;

mHolder = getHolder();

mHolder.addCallback(this);

mHolder.setFormat(PixelFormat.TRANSPARENT);

然后实现我们的绘制线程:

private class DrawThread extends Thread {

// 用来停止线程的标记

private boolean isRunning = false;

public void setRunning(boolean running) {

isRunning = running;

}

@Override

public void run() {

Canvas canvas;

// 无限循环绘制

while (isRunning) {

if (mType != null && mViewWidth != 0 && mViewHeight != 0) {

canvas = mHolder.lockCanvas();

if (canvas != null) {

mType.onDraw(canvas);

if (isRunning) {

mHolder.unlockCanvasAndPost(canvas);

} else {

// 停止线程

break;

}

SystemClock.sleep(1);

}

}

}

}

}

从上面的代码可以看出 SurfaceView 的更新流程具体为:

// 锁定画布并获得 canvas

canvas = mHolder.lockCanvas();

// 在 canvas 上进行绘制

mType.onDraw(canvas);

// 解除锁定并提交更改

mHolder.unlockCanvasAndPost(canvas);

绘制线程代码量不多,因为具体的绘制代码在 mType.onDraw(canvas)中,mType 是我们自己定义的一个接口,代表一种天气类型:

public interface WeatherType {

void onDraw(Canvas canvas);

void onSizeChanged(Context context, int w, int h);

}

这样要想实现不同的天气类型,只要实现这个接口重写 onDraw 和 onSizeChanged 方法即可,这里我们实现的是下雨的效果,所以实现了一个 RainTypeImpl 类:

public class RainTypeImpl extends BaseType {

// 背景

private Drawable mBackground;

// 雨滴集合

private ArrayList mRains;

// 画笔

private Paint mPaint;

public RainTypeImpl(Context context, DynamicWeatherView dynamicWeatherView) {

super(context, dynamicWeatherView);

init();

}

private void init() {

mPaint = new Paint();

mPaint.setAntiAlias(true);

mPaint.setColor(Color.WHITE);

// 这里雨滴的宽度统一为3

mPaint.setStrokeWidth(3);

mRains = new ArrayList<>();

}

@Override

public void generate() {

mBackground = getContext().getResources().getDrawable(R.drawable.rain_sky_night);

mBackground.setBounds(0, 0, getWidth(), getHeight());

for (int i = 0; i < 60; i++) {

RainHolder rain = new RainHolder(

getRandom(1, getWidth()),

getRandom(1, getHeight()),

getRandom(dp2px(9), dp2px(15)),

getRandom(dp2px(5), dp2px(9)),

getRandom(20, 100)

);

mRains.add(rain);

}

}

private RainHolder r;

@Override

public void onDraw(Canvas canvas) {

clearCanvas(canvas);

// 画背景

mBackground.draw(canvas);

// 画出集合中的雨点

for (int i = 0; i < mRains.size(); i++) {

r = mRains.get(i);

mPaint.setAlpha(r.a);

canvas.drawLine(r.x, r.y, r.x, r.y + r.l, mPaint);

}

// 将集合中的点按自己的速度偏移

for (int i = 0; i < mRains.size(); i++) {

r = mRains.get(i);

r.y += r.s;

if (r.y > getHeight()) {

r.y = -r.l;

}

}

}

private class RainHolder {

/**

* 雨点 x 轴坐标

*/

int x;

/**

* 雨点 y 轴坐标

*/

int y;

/**

* 雨点长度

*/

int l;

/**

* 雨点移动速度

*/

int s;

/**

* 雨点透明度

*/

int a;

public RainHolder(int x, int y, int l, int s, int a) {

this.x = x;

this.y = y;

this.l = l;

this.s = s;

this.a = a;

}

}

}

代码不难,基本都有注释,RainHolder 对象代表一个雨滴,每绘制一次然后改变雨滴的位置,然后准备下一次绘制,来实现雨滴的移动。

BaseType 类是我们的一个抽象基类,实现了 DynamicWeatherView.WeatherType接口,内部有一些公共方法,具体可以看 Demo 中的代码。

最后我们的 Activity 代码:

public class MainActivity extends Activity {

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

DynamicWeatherView mDynamicWeatherView = (DynamicWeatherView) findViewById(R.id.dynamic_weather_view);

mDynamicWeatherView.setType(new RainTypeImpl(this, mDynamicWeatherView));

}

}

今后要想实现不同的天气类型,只需要继承 BaseType 类重写相关方法即可。

源码下载:点击这里

总结

以上就是这篇文章的全部内容了,希望本文的内容对各位Android开发者们能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对脚本之家的支持。

android 天气动画,Android利用SurfaceView实现下雨的天气动画效果相关推荐

  1. java程序 下雨,利用SurfaceView实现下雨与下雪动画效果详解(Kotlin语法)

    前言 最近打算做一波东西巩固一下自己近期所学所得.话不多说,先看一下最终完成的效果图: 下雨.gif 这里比较懒--第二个图片中还是降雨--不过这不是关键点-- 下雪.gif 录制的mp4,转成了gi ...

  2. html用css完成动画效果图,利用CSS Sprite实现PNG图片动画

    利用CSS Sprite实现PNG图片动画 12月 6, 2012 评论 (6) Sponsor 如题,今天将会和大家讲解如何利用CSS Sprite(CSS雪碧)来实现PNG图片动画,就像GIF一样 ...

  3. html微信拆红包动画特效,利用jQuery实现微信红包领取动画特效

    特效描述:利用jQuery实现 微信红包 领取动画特效.利用jQuery实现微信红包领取动画特效 代码结构 1. 引入CSS 2. 引入JS 3. HTML代码 点击打开 $(function () ...

  4. ffmpeg实战教程(七)Android CMake avi解码后SurfaceView显示

    ffmpeg实战教程(七)Android CMake avi解码后SurfaceView显示 本篇我们实现Android平台解码avi并用SurfaceView播放. 先上图看效果: 思路:  1.把 ...

  5. android js 开屏动画,利用Flutter实现“孔雀开屏”的动画效果

    前言 今天分享一个类似"孔雀开屏"的动画效果,打开新的页面时,新的页面从屏幕右上角以圆形逐渐打开到全屏. 先来看下具体的效果 不知道这种效果大家叫什么名字?如果有更合适的名字可以在 ...

  6. Android 利用属ObjectAnimator,AnimatorSet性动画绘制一个弹球,加速下落,到底部时挤压,然后减速上弹...

    属性动画主要的几个类介绍: 1.ValueAnimator:这个类提供了一个简单的计时引擎运行动画动画计算值和设置目标对象.注意:使用该类时一般都是用:ObjectAnimator,而基于Object ...

  7. 自绘动画android,(译)android利用Canvas和几何学绘制几何动画

    1 创建圆形动画 首先需要画一些同心圆,并添加动画将同心圆的半径逐渐增加,即从同心圆中心向四周扩散的动画. 需要定义一些属性包括:同心圆间隔.圆线颜色.圆线宽度: 1dp @color/black 1 ...

  8. android开发 鱼动画,如何使用SurfaceView实现鱼儿游动动画

    本文实例为大家分享了使用SurfaceView实现动画的具体代码,供大家参考,具体内容如下 与自定义view绘图进行对比: 1.view绘图没有双缓冲机制,而surfaceview有 2.view绘图 ...

  9. android之利用surfaceView实现自定义水印相机

    android之利用surfaceView实现自定义水印相机 知识点 1.自定义相机+预览相机 2.截屏拍照加水印 3.关于不使用intent来传输图片 4.关于大家说要demo的,因为这里是项目里头 ...

最新文章

  1. IDEA中将代码块封装为方法,IDEA代码重构快捷键
  2. 刷题一个4ms的程序,代码如何优化到3ms再到2ms?
  3. 南工程计算机学院贴吧,【计算机工程学院答疑转帖】
  4. 七牛云——对象存储私有空间下载凭证认证失败401[“error“:“download token auth failed“]解决方案
  5. HTML5概述、标签
  6. (六)将样式转换模型从TensorFlow转换为TensorFlow Lite
  7. Spark中加载本地(或者hdfs)文件以及SparkContext实例的textFile使用
  8. CIO圈子—CIO成长交流的平台
  9. 利用Excel制作库房管理系统
  10. 安卓Activity劫持与反劫持
  11. MyBatis拦截器执行顺序
  12. 后缀树后缀数组LCP
  13. 宝鸡渭滨区11―12学年度第一学期高二期末联考试卷高二地理
  14. js里的一些even事件
  15. 有关H5第六章的背景与阴影介绍
  16. 致丰巢:品牌管理,才是长久之计
  17. Google Earth Engine(GEE)批量下载不透水面数据
  18. jQuery ajax 请求 和 Submit 提交 form 表单
  19. 电气隔离 电源模块 升压/充电 实测案例 150V 30W 带四个220UF电解电容并联 300ms
  20. 华硕笔记本扇热声音大

热门文章

  1. Java Maven Tomcat使用Tesseract-OCR文字识别(Tess4j)
  2. 苹果的“BIOS”设置
  3. asp.net 微信企业号 微企办公系统-部门人员同步
  4. c++封装Rector
  5. 华为WLAN产品介绍与组网(包括capwap隧道,ap上线,STA上线,组网方式,转发方式)
  6. c++学生兴趣管理系统(仅作学术探讨,请勿搬运抄袭)
  7. linux无法访问root文件夹,asp.net core 2.1部署到Linux无法访问wwwroot文件夹中的资源...
  8. 中国SaaS产业越来越确定了
  9. 【Kevin Learn QMUI】--> QMUIBottomSheet
  10. 互联网公司部门鄙视链!