简介

一直对墨迹天气的绚丽的场景蛮感兴趣的,趁有时间,自己就高仿了其中的一个场景,其他场景呢,也是类似的,主要是写对象的AI也就是逻辑了。

先看看效果吧,动态效果比较坑,太模糊

高清图

代码分析

来看看代码结构吧

这里使用了SurfaceView而不是用的view,其实这个天气的场景绘制更像是游戏开发,使用SurfaceView会更灵活。

    public SceneSurfaceView(Context context, AttributeSet attrs) {super(context, attrs);surfaceHolder = getHolder();surfaceHolder.addCallback(this);setFocusable(true);setFocusableInTouchMode(true);this.setKeepScreenOn(true);
}

这就是构造方法了,实现 SurfaceHolder.Callback 来监听事件

    @Overridepublic void surfaceCreated(SurfaceHolder holder) {Log.d("weather", "surfaceCreated");if (renderThread == null) {renderThread = new RenderThread(surfaceHolder, getContext());renderThread.start();}
}

在 surface 创建回调中, 我们生成了一个 RenderThread 线程来专门做逻辑与绘制。

    @Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {width = getMeasuredWidth();height = getMeasuredHeight();super.onMeasure(widthMeasureSpec, heightMeasureSpec);Log.d("weather", "onMeasure width=" + width + ",height=" + height);if (renderThread != null) {renderThread.setWidth(width);renderThread.setHeight(height);}
}

记录下测量的宽高

    @Overridepublic void surfaceDestroyed(SurfaceHolder holder) {Log.d("weather", "surfaceDestroyed");renderThread.getRenderHandler().sendEmptyMessage(1);
}

销毁的时候要发一个消息,具体做什么,下面在来说

下面是RenderThread源码

public class RenderThread extends Thread {private Context context;private SurfaceHolder surfaceHolder;private RenderHandler renderHandler;private Scene scene;public RenderThread(SurfaceHolder surfaceHolder, Context context) {this.context = context;this.surfaceHolder = surfaceHolder;scene = new Scene(context);//add scene/actorscene.setBg(BitmapFactory.decodeResource(context.getResources(), R.drawable.bg0_fine_day));scene.add(new BirdUp(context));scene.add(new CloudLeft(context));scene.add(new CloudRight(context));scene.add(new BirdDown(context));scene.add(new SunShine(context));}@Overridepublic void run() {Log.d("weather", "run");//在非主线程使用消息队列Looper.prepare();renderHandler = new RenderHandler();renderHandler.sendEmptyMessage(0);Looper.loop();}public RenderHandler getRenderHandler() {return renderHandler;}public class RenderHandler extends Handler {@Overridepublic void handleMessage(Message msg) {switch (msg.what) {case 0:if (scene.getWidth() != 0 && scene.getHeight() != 0) {draw();}renderHandler.sendEmptyMessage(0);break;case 1:Looper.myLooper().quit();break;}}}private void draw() {Canvas canvas = surfaceHolder.lockCanvas();if (canvas != null) {scene.draw(canvas);surfaceHolder.unlockCanvasAndPost(canvas);}}public void setWidth(int width) {scene.setWidth(width);}public void setHeight(int height) {scene.setHeight(height);}
}

在构造方法中添加了场景背景,上下两个鸟,左右各一个云彩和阳光。

这里在run方法里生成了一个线程的消息队列,注意额不是主线程的,其实也可以在里面搞个while循环,就像一般的游戏处理一样, 但是如果使用消息队列,会更轻巧有效。

大家再来看看RenderHandler

情况分2种,一个是绘制的一个是退出的,基本也就这2种了。

还记得在surfaceDestroyed中调用的退出吧,现在就在这了,呵呵

然后就是最重要的draw方法了

绘制是在Scene中操作的,来看看代码

public class Scene {private Context context;private int width;private int height;private Bitmap bg;private List<Actor> actors = new ArrayList<Actor>();private Paint paint;public Scene(Context context) {this.context = context;paint = new Paint();paint.setAntiAlias(true);}public void setBg(Bitmap bg) {this.bg = bg;}public void add(Actor actor) {actors.add(actor);}public void draw(Canvas canvas) {canvas.drawBitmap(bg, new Rect(0, 0, bg.getWidth(), bg.getHeight()), new Rect(0, 0, width, height), paint);for (Actor actor : actors) {actor.draw(canvas,width,height);}
}

可以在场景中绘制一个背景图和 Actor 列表

Actor是啥呢,就是对象呗,像鸟啊,云啊,雨啊等等吧

public abstract class Actor {protected Context context;protected Matrix matrix = new Matrix();protected Actor(Context context) {this.context = context;}public abstract void draw(Canvas canvas, int width, int height);
}

这是一个抽象类, Context  可以加载资源文件, Matrix  来描述对象的变换,抽象方法 draw 就是咱们的逻辑和绘制方法喽

来看看上边的那个小鸟的代码吧

public class BirdUp extends Actor {private static final int[] imgs = new int[]{R.drawable.finedayup_1, R.drawable.finedayup_2, R.drawable.finedayup_3, R.drawable.finedayup_4, R.drawable.finedayup_5, R.drawable.finedayup_6, R.drawable.finedayup_7, R.drawable.finedayup_8};float initPositionX;float initPositionY;boolean isInit;List<Bitmap> frames;RectF box;RectF targetBox;int curFrameIndex;long lastTime;Paint paint = new Paint();protected BirdUp(Context context) {super(context);frames = new ArrayList<Bitmap>();box = new RectF();targetBox = new RectF();paint.setAntiAlias(true);}@Overridepublic void draw(Canvas canvas, int width, int height) {//逻辑处理//初始化if (!isInit) {initPositionX = width * 0.117F;initPositionY = height * 0.35F;matrix.reset();matrix.postTranslate(initPositionX, initPositionY);for (int res : imgs) {frames.add(BitmapFactory.decodeResource(context.getResources(), res));}box.set(0, 0, frames.get(0).getWidth(), frames.get(0).getHeight());isInit = true;lastTime = System.currentTimeMillis();return;}//移动matrix.postTranslate(2, 0);//边界处理matrix.mapRect(targetBox, box);if (targetBox.left > width) {matrix.postTranslate(-targetBox.right, 0);}//取得帧动画图片long curTime = System.currentTimeMillis();curFrameIndex = (int) ((curTime - lastTime) / 500 % 8);Bitmap curBitmap = frames.get(curFrameIndex);//绘制canvas.save();canvas.drawBitmap(curBitmap, matrix, paint);canvas.restore();}
}

主要逻辑就在 draw 了, 注释写的也比较清除了,先初始化操作,加载资源,设定起始位置,然后就是每帧的移动逻辑,和边界逻辑处理,就是跑到最右边,再把他拉到最左边,呵呵,下面是小鸟动画的处理,我这里是 500 毫秒更换一下图片,也就是说看到的小鸟的动画,其实是隔 500 毫秒更换了一次图片产生的效果,下面就只绘制了,好了 so easy  吧 !

这里要特别说明一个方法matrix.mapRect(targetBox, box);这个方法比较重要,大家以后肯定会经常用到,意思是啥呢,box这个参数是原始的图片大小数据,targetBox是经过Matrix矩阵变换后产生的数据。

好了,下面的鸟其实跟上面的逻辑一样的,只是起始位置不一样。

云彩呢,和小鸟逻辑也差不多,但是需要注意一个地方, 我把云彩给放大了2倍

            matrix.reset();matrix.setScale(2f, 2f);matrix.mapRect(targetBox, box);matrix.postTranslate(initPositionX - targetBox.width() / 2, initPositionY - targetBox.height() / 2);

这里初始位置呢, 我也根据放大后的宽和高进行了处理,大家注意啊,先放缩和先设置位置,出来的效果是不一样的。 大家可以自行试试效果。

现在来看看我们的阳光代码吧

这里就贴一些关键代码了, 全部代码可以在我的github上下载

        //旋转matrix.mapRect(targetBox, box);matrix.postRotate(0.5F, targetBox.centerX(), targetBox.centerY());//透明度变化if (alphaUp) {alpha++;} else {alpha--;}if (alpha >= 255) {alphaUp = false;}if (alpha <= 0) {alphaUp = true;}paint.setAlpha(alpha);//绘制canvas.drawBitmap(frame, matrix, paint);

主要就是介绍一下,使用矩阵来进行旋转操作和透明度操作怎么来做。这里要注意一下的是旋转的时候,要设置中心点。

结束语

好了,代码说的也差不多啦,知识点也都过了一下。回过头来看看,要实现这么一个效果也不是那么难是吧。 呵呵。 当然了实现的还是比较仓促的,就是简单的一个架子和一个场景,如果感兴趣的话可以添加更多的对象AI逻辑,更多的场景。其实如果做到最后优化好的话应该是这样的一个情况,每个场景一个xml或者其他脚本语言吧,然后解析这个xml来动态生成一个场景。当然也不是很难。真正做天气的话,可以这样做。

Github地址

https://github.com/wu928320442/MojiWeather

高仿墨迹天气 白天晴天相关推荐

  1. Android之高仿墨迹天气桌面组件(AppWidgetProvider) .

    Android之高仿墨迹天气桌面组件(AppWidgetProvider) . 点击:382 发布时间:2012-10-03 更多0 相信墨迹天气,大家都见过,他在时间显示和天气界面上,很吸引人,今天 ...

  2. 高仿墨迹天气“我”页面

    看到墨迹天气的"我"页面比较炫酷,处于好奇,就写了一个demo模仿一下. 1,实现效果 实现的效果分三个部分来说明,首先是下拉到最大高度,个人信息界面会产生一个回弹的效果,然后是滚 ...

  3. (4.0.24.2)Android之桌面组件App Widget案例之高仿墨迹天气桌面组件

    相信墨迹天气,大家都见过,他在时间显示和天气界面上,很吸引人,今天我就来模仿一下墨迹天气的桌面组件,但是由于谷歌在天朝频频被墙的缘故,所以我在今天测试的时候,解析xml文件的网页打不开,所以天气显示出 ...

  4. 高仿墨迹天气-天鹰气象

            本项目主要设计了一个Android天气气象软件,从网络上获取相关天气信息后展示给用户,主要进行解析json.界面设计.动画优化等工作.所开发软件能够达到如下预期效果: (1)能够根据用 ...

  5. Android 高仿墨迹天气“我”页面

    1,实现效果  转自:http://blog.csdn.net/huweigoodboy/article/details/47301197 实现的效果分三个部分来说明,首先是下拉到最大高度,个人信息界 ...

  6. 墨迹天气php,Android_仿墨迹天气在Android App中实现自定义zip皮肤更换,在这里谈一下墨迹天气的换肤 - phpStudy...

    仿墨迹天气在Android App中实现自定义zip皮肤更换 在这里谈一下墨迹天气的换肤实现方式,不过首先声明我只是通过反编译以及参考了一些网上其他资料的方式推测出的换肤原理, 在这里只供参考. 若大 ...

  7. Android 打造自己的个性化应用(四):仿墨迹天气实现--自定义扩展名的zip格式的皮肤...

    在这里谈一下墨迹天气的换肤实现方式,不过首先声明我只是通过反编译以及参考了一些网上其他资料的方式推测出的换肤原理, 在这里只供参考. 若大家有更好的方式, 欢迎交流. 墨迹天气下载的皮肤就是一个zip ...

  8. Android 仿墨迹天气24小时预报

    效果目标: 1.现在到未来24小时温度点连成贝塞尔曲线 2.指示器跟随选中每小时空气质量移动 3.合并相同风力与天气icon 4.显示区域的icon在屏幕可视范围内左右居中 5.显示区域的风力等级在屏 ...

  9. android 自定义皮肤,仿墨迹天气在Android App中实现自定义zip皮肤更换

    在这里谈一下墨迹天气的换肤实现方式,不过首先声明我只是通过反编译以及参考了一些网上其他资料的方式推测出的换肤原理, 在这里只供参考. 若大家有更好的方式, 欢迎交流. 墨迹天气下载的皮肤就是一个zip ...

最新文章

  1. [总结]Asp.net中的页面乱码的问题
  2. SAP 年结(转载)
  3. ArcGIS中的坐标系定义与转换 (转载)
  4. java环境变量立即生效_win7批处理环境变量立即生效
  5. ubuntu 跟xshell的问题
  6. Python+selenium第一个自动化脚本
  7. 怎样用mysql查询测试_如何测试数据库查询优化器
  8. JS-数据类型转换-运算符
  9. Vue的常用指令有哪些,分别是什么作用?
  10. cimiss数据_CIMISS数据下载小助手
  11. Leetcode-5063 Last Stone Weight(最后一块石头的重量)
  12. Linux查看端口命令
  13. 我们梳理了国内外逾80家公司,发现6大关键趋势 | 36氪眼健康行业报告
  14. canvas实现简单画板
  15. [黑群晖经典教程] 一步一步建立自己的黑群晖
  16. mvc html禁用文本框,如何在MVC htmlAttribute中設置禁用
  17. GOP I帧和IDR帧
  18. 微信小程序之生成海报保存本地
  19. TencentOS-Tiny在苹果MacOS初上手
  20. 贷后评分模型的三种细分应用

热门文章

  1. 【CSDN|每日一练】吃!吃!吃!
  2. ps4和php,PS4《战神》通关心得分享与给新手的游玩建议
  3. 保研面试/考研复试英文自我介绍模板(30秒、1分钟、2分钟、3分钟)
  4. 指令集os系统部署用户应用教程
  5. 中国2-己氧乙醇市场发展现状与投资前景分析报告2022-2028年
  6. 《仙剑奇侠传4》仙剑问答全答案
  7. 【学习笔记】明哥聊求职第二季
  8. Java 8 String类API 手册 翻译 中英文对照
  9. 斐波拉契的第100项
  10. ipad 导入电脑中文件