(本博客为原创:http://www.cnblogs.com/linguanh/)

目录:

  效果展示

  感想

  代码拆解

  开源地址

效果展示

  有没有兴趣继续看下去,直接看下"颜值"是第一步了。依次对应:下雨,飘雪,红包雨,碰撞球

   

  上面是图片,这里再发个视频链接:http://pan.baidu.com/s/1miyPn76

感想

  16年总算过去了,跟各位猿友有说句祝福吧,新的一年少加点班,身体健康,钱能赚多少就尽量赚。

  之前看博客园,很多发纯感想的,都被推荐了好几天,说实话,我几乎一拉到底,就看有没有点↓的。

  公司放假时间是在23号,也就明天了,大四实习到现在,一直很忙,这段时间也是我在编程层面上学到了比较多东西的阶段,上面的自定义View是Android的,完成它们是在实习上班期间挤出时间做的,最初的初衷是想把第四个碰撞球的效果加入到毕设里面,现在总算是实现了,过程遇到很多问题,球体的碰撞处理比想象中麻烦很多,前三个比较简单,也是微信,QQ的下表情原理吧,我猜应该是。。。

  毕设最终也会开源,还请大家留意我 GitHbub,这将会是一个集合非第三方IM和仿朋友圈+golang制作服务端等等知识的社交APP。

代码拆解

  如果你仔细看了上面的四张效果图,你会发现,前三张是没碰撞效果处理的,而第四张是具备的。这也是我要区分实现的效果,目的是为了表明,不仅可以不碰撞还可以选择碰。

  同时,飘雪和红包雨,事实也仅仅是图片的不同,这就对了。你只需要修改图片就能实现完全自定义,爱下什么下什么。

  言归正传,整体使用了 适配器设计模式。代码是很简练易懂的,可以看看我的目录结构。

  

  基类是一个暴露绘制和逻辑抽象方法的View子类,所有自定义View需要继承它。子类只需要关注自己要绘制什么,以及我要绘制的东西怎么去不断地改变,逻辑改变设计在一个 Thread 线程里面,采用 postInvalidate 通知 UI 刷新。

 /**
* Created by LinGuanHong on 2017/1/15.
*
* My GitHub : https://github.com/af913337456/
*
* My Blog : http://www.cnblogs.com/linguanh/
*
*/ public abstract class BaseView extends View { protected String TAG = "zzzzz";
private static final int sleepTime = 30;
private RefreshThread refreshThread = null; public BaseView(Context context) {
super(context);
} public BaseView(Context context, AttributeSet attrs) {
super(context, attrs);
} public abstract void drawSub(Canvas canvas); public abstract void baseInit(int width,int height); public abstract void logic(); @Override
protected final void onDraw(Canvas canvas) {
if(refreshThread == null){
refreshThread = new RefreshThread();
refreshThread.start();
}else{
drawSub(canvas);
}
} @Override
protected void onDetachedFromWindow() {
running = false;
super.onDetachedFromWindow();
} private boolean running = true;
private class RefreshThread extends Thread{ @Override
public void run() {
baseInit(getWidth(),getHeight());
while (running){
try{
logic();
postInvalidate();
Thread.sleep(sleepTime);
}catch (Exception e){
Log.d(TAG,e.toString());
}
}
}
}
}

   BaseView 已经是一个可以直接继承的父类了,如果仅仅只是绘制一些比较简单逻辑的自定义View,继承它足以,但是要实现上述的效果,还需要添加多一个抽象类,无论是雨景还是雪景,它们都是个体的集合,也就是说,我们需要一个"景"的抽象。

  ShowView 是一个具备泛型的抽象类,它是景色的制作者,至于是什么景,由你来决定,也就是泛型的传入。例如,我要制造雨景,那么我就传入雨点,雪景就是雪块

 /**
* Created by LinGuanHong on 2017/1/15.
*
* My GitHub : https://github.com/af913337456/
*
* My Blog : http://www.cnblogs.com/linguanh/
*
*/ public abstract class ShowView<T extends BaseItem> extends BaseView { protected List<T> itemList = new ArrayList<>();
protected int size = 1; public ShowView(Context context) {
super(context);
} /** 子类实现布局必须要重写这个构造方法 */
public ShowView(Context context, AttributeSet attrs) {
super(context, attrs);
} @Override
public void drawSub(Canvas canvas) {
for(T t:itemList){
t.draw(canvas);
}
} @Override
public void logic() {
beforeLogicLoop();
for(T t:itemList){
t.move();
}
} public abstract void beforeLogicLoop();
public abstract T getItem(int width, int height,Resources resources);
public abstract int getCount(); @Override
public void baseInit(int width, int height) {
size = getCount();
Resources resources = getResources();
for(int i = 0; i< size; i++){
itemList.add(getItem(width,height,resources));
}
} }

  由于我们的景色里面的个体可能是各种各样,那么为了使他们都能具备一些公共的属性,需要再抽象一个基础的个体类,共不同的景色个体继承。

 /**
* Created by LinGuanHong on 2017/1/15.
*
* My GitHub : https://github.com/af913337456/
*
* My Blog : http://www.cnblogs.com/linguanh/
*
* 公共的属性和行为
*
*/ public abstract class BaseItem { protected int width,height; /** 景内宽高 */
protected Resources resources; public BaseItem(int width,int height,Resources resources){
this.width = width;
this.height = height;
this.resources = resources;
} public abstract void draw(Canvas canvas); /** 显示 */
public abstract void move(); /** 运动 */ }

  OK,到这里基础的类都搞定了,为什么说是适配器模式呢,其实 BaseItem 就是 ViewHolder,ShowView 是 BaseAdapter,下面放下雨的Item 类和雨景。

  注意注释,代码很简练易懂!

 /**
* Created by LinGuanHong on 2017/1/15.
*
* 造雨,造多少个,160个,具体是什么雨,交给 item 实现
*
*/ public class RainView extends ShowView<RainItem> { public RainView(Context context) {
super(context);
} public RainView(Context context, AttributeSet attrs) {
super(context, attrs);
} @Override
public void beforeLogicLoop() { } @Override
public RainItem getItem(int width, int height, Resources resources) {
return new RainItem(width,height,resources); /** 要造的雨,是什么雨就在这里传入 */
} @Override
public int getCount() { /** 要制作的雨数目 */
return 160;
}
}

  我要制作的雨,随机数可以自定义。

 /**
* Created by LinGuanHong on 2017/1/15.
*/ public class RainItem extends BaseItem { private float opt;
private int sizeX,sizeY; /** 充当角度 */
private int startX,startY,stopX,stopY;
private Paint paint;
private Random random; public RainItem(int width, int height, Resources resources) {
super(width,height,resources);
init();
loopInit();
} @Override
public void move() {
startX += sizeX * opt;
stopX += sizeX * opt; startY += sizeY * opt;
stopY += sizeY * opt;
if(startY > height){
loopInit();
}
} @Override
public void draw(Canvas canvas) {
Log.d("zzzzz","drawView "+startX+" "+startY+" "+stopX+" "+stopY);
canvas.drawLine(startX,startY,stopX,stopY,paint);
} private void loopInit(){
sizeX = 1 + random.nextInt(10);
sizeY = 10 + random.nextInt(20); startX = random.nextInt(width );
startY = random.nextInt(height); opt = 0.2f + random.nextFloat(); stopX = startX + sizeX;
stopY = startY + sizeY;
} private void init(){
paint = new Paint(Paint.ANTI_ALIAS_FLAG); /** 抗锯齿 */
paint.setColor(0xffffffff); /** a,r,g,b 255,255,255,255 */ random = new Random();
} }

  到这里总结一下,如果你想实现自己的自定义View,不妨直接继承 BaseView,然后写你自己的 Item,就可以了。

开源地址

  我的:https://github.com/af913337456/XView

  

2017了,回家前 "年末" 分享:下雨,飘雪,红包雨,碰撞球,自定义View的更多相关文章

  1. 2017年排名前15的数据科学python库

    2017年排名前15的数据科学python库 2017-05-22 Python程序员 Python程序员 Python程序员 微信号 pythonbuluo 功能介绍 最专业的Python社区,有每 ...

  2. Android自定义View前传-View的三大流程-Measure

    Android自定义View前传-View的三大流程-Measure 参考 <Android开发艺术探索> https://developer.android.google.cn/refe ...

  3. 3D语音天气球(源码分享)——创建可旋转的3D球

    开篇废话: 在9月份时参加了一个网站的比赛,比赛的题目是需要使用第三方平台提供的服务做出创意的作品. 于是我选择使用语音服务,天气服务,Unity3D,Android来制作一个3D语音天气预报,我给它 ...

  4. android 自定义view 前的基础知识

    本篇文章是自己自学自定义view前的准备,具体参考资料来自 Android LayoutInflater原理分析,带你一步步深入了解View(一) Android视图绘制流程完全解析,带你一步步深入了 ...

  5. 2017最新的Python教程分享

    Python在数据科学盛行的今天,其易于阅读和编写的特点,越来越受编程者追捧.在IEEE发布的2017年编程语言排行榜中,Python也高居首位.如果你有学Python的计划,快来看看小编分享的Pyt ...

  6. 2017埙箫简谱清单分享(附音频Demo)

    前言 习箫五载,略有所获,皆在坚持. 本博文记录旨在记录练习过程中所录制的Demo以供自省.自娱.自乐,同时记录.分享简谱与箫友(目前为简谱,日后学会线谱后会添加相应谱子分类). 简谱 &&a ...

  7. 回家前的挣扎——SQLite增删改查

    引言 最后一天,公司就两个人,也不知道弄点什么,就在网上找了Sqlite的文档,看了看,这里也是现学现卖,给自己找点事做,感觉时间过得还是比较快的,不然焦急等待,滋味不好受啊. SQLite简介 SQ ...

  8. 2015年末分享:利用RS修改用户密码

    马上就要2016农历新年了,送点什么给大家呢?我觉得还是分享点技术吧.前不久用户在抱怨为什么登录Cognos Connection的密码不能让我们自己改?相信Cognos开发的很多人知道,Cognos ...

  9. 简单跳转到微信分享,基于libWeiChatSDK 和简单的自定义UIActivityViewController

    一.自定义UIActivity: 如果想要自定义UIActivity必须知道UIActivityViewController.首先这个类主要是用于接受字符串,RUL类型和图片类型的数据用于分享和操作的 ...

随机推荐

  1. 高橋君とホテル / Tak and Hotels

    高橋君とホテル / Tak and Hotels Time limit : 3sec / Stack limit : 256MB / Memory limit : 256MB Score : 700  ...

  2. Cow Rectangles

    Cow Rectangles 题目描述 The locations of Farmer John's N cows (1 <= N <= 500) are described by dis ...

  3. 改变nova-compute默认位置的方法

    # cat /etc/nova/nova.conf |grep -n state_path|grep -v '#'314:state_path=/var/lib/nova

  4. PAT 天梯赛 L2-002 链表去重

    模拟单链表的增删操作 题目链接:https://www.patest.cn/contests/gplt/L2-002 题解 最开始我脑抽用map模拟单链表进行操作,因为这样可以节约空间,并且用了cin ...

  5. flexpaper二次开发

    1.首先下载FlexPaper的源码.下载地址 2.本人不懂flash,只是百度下,然后自己瞎弄弄的.我用的flash build 4.5 提供个key:1499-4181-9296-6452-299 ...

  6. 搭建firefly服务端遇到的问题

    1 pylinter pylinter could not automatically determined the path to "lint.py" 这个错误通过安装pylin ...

  7. Express 简介

    Express 简介 Express 是一个简洁而灵活的 node.js Web应用框架, 提供了一系列强大特性帮助你创建各种 Web 应用,和丰富的 HTTP 工具. 使用 Express 可以快速 ...

  8. OPENCV条形码检测与识别

    条形码是当前超市和部分工厂使用比较普遍的物品,产品标识技术,使用摄像头检测一张图片的条形码包含有两个步骤,第一是定位条形码的位置,定位之后剪切出条形码,并且识别出条形码对应的字符串,然后就可以调用网络 ...

  9. MySQL 同步状态

    Exec_Master_Log_Pos: The position of the last event executed by the SQL thread from the master's bin ...

  10. STM8S awu及看门狗IWDG WWDG应用(转)

    源:STM8S awu及看门狗IWDG WWDG应用 AWU的应用(用库函数完成的) //切记要开启中断 且在中断函数中 AWU_GetFlagStatus(); 来清除中断 void AWU_SET ...