zoukankan      html  css  js  c++  java
  • 2017了,回家前 "年末" 分享:下雨,飘雪,红包雨,碰撞球,自定义View

    (本博客为原创: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 刷新。

     1 /**
     2  * Created by LinGuanHong on 2017/1/15.
     3  *
     4  * My GitHub : https://github.com/af913337456/
     5  *
     6  * My Blog   : http://www.cnblogs.com/linguanh/
     7  *
     8  */
     9 
    10 public abstract class BaseView extends View {
    11 
    12     protected String TAG = "zzzzz";
    13     private static final int sleepTime = 30;
    14     private RefreshThread refreshThread = null;
    15 
    16     public BaseView(Context context) {
    17         super(context);
    18     }
    19 
    20     public BaseView(Context context, AttributeSet attrs) {
    21         super(context, attrs);
    22     }
    23 
    24     public abstract void drawSub(Canvas canvas);
    25 
    26     public abstract void baseInit(int width,int height);
    27 
    28     public abstract void logic();
    29 
    30     @Override
    31     protected final void onDraw(Canvas canvas) {
    32         if(refreshThread == null){
    33             refreshThread = new RefreshThread();
    34             refreshThread.start();
    35         }else{
    36             drawSub(canvas);
    37         }
    38     }
    39 
    40     @Override
    41     protected void onDetachedFromWindow() {
    42         running = false;
    43         super.onDetachedFromWindow();
    44     }
    45 
    46     private boolean running = true;
    47     private class RefreshThread extends Thread{
    48 
    49         @Override
    50         public void run() {
    51             baseInit(getWidth(),getHeight());
    52             while (running){
    53                 try{
    54                     logic();
    55                     postInvalidate();
    56                     Thread.sleep(sleepTime);
    57                 }catch (Exception e){
    58                     Log.d(TAG,e.toString());
    59                 }
    60             }
    61         }
    62     }
    63 }
    View Code

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

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

     1 /**
     2  * Created by LinGuanHong on 2017/1/15.
     3  *
     4  * My GitHub : https://github.com/af913337456/
     5  *
     6  * My Blog   : http://www.cnblogs.com/linguanh/
     7  *
     8  */
     9 
    10 public abstract class ShowView<T extends BaseItem> extends BaseView {
    11 
    12     protected List<T> itemList = new ArrayList<>();
    13     protected int size = 1;
    14 
    15     public ShowView(Context context) {
    16         super(context);
    17     }
    18 
    19     /** 子类实现布局必须要重写这个构造方法 */
    20     public ShowView(Context context, AttributeSet attrs) {
    21         super(context, attrs);
    22     }
    23 
    24     @Override
    25     public void drawSub(Canvas canvas) {
    26         for(T t:itemList){
    27             t.draw(canvas);
    28         }
    29     }
    30 
    31     @Override
    32     public void logic() {
    33         beforeLogicLoop();
    34         for(T t:itemList){
    35             t.move();
    36         }
    37     }
    38 
    39     public abstract void beforeLogicLoop();
    40     public abstract T getItem(int width, int height,Resources resources);
    41     public abstract int getCount();
    42 
    43     @Override
    44     public void baseInit(int width, int height) {
    45         size = getCount();
    46         Resources resources = getResources();
    47         for(int i = 0; i< size; i++){
    48             itemList.add(getItem(width,height,resources));
    49         }
    50     }
    51 
    52 }
    View Code

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

     1 /**
     2  * Created by LinGuanHong on 2017/1/15.
     3  *
     4  * My GitHub : https://github.com/af913337456/
     5  *
     6  * My Blog   : http://www.cnblogs.com/linguanh/
     7  *
     8  * 公共的属性和行为
     9  *
    10  */
    11 
    12 public abstract class BaseItem {
    13 
    14     protected int width,height;      /** 景内宽高 */
    15     protected Resources resources;
    16 
    17     public BaseItem(int width,int height,Resources resources){
    18         this.width  = width;
    19         this.height = height;
    20         this.resources = resources;
    21     }
    22 
    23     public abstract void draw(Canvas canvas); /** 显示 */
    24     public abstract void move();     /** 运动 */
    25 
    26 }

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

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

     1 /**
     2  * Created by LinGuanHong on 2017/1/15.
     3  *
     4  * 造雨,造多少个,160个,具体是什么雨,交给 item 实现
     5  *
     6  */
     7 
     8 public class RainView extends ShowView<RainItem> {
     9 
    10 
    11     public RainView(Context context) {
    12         super(context);
    13     }
    14 
    15     public RainView(Context context, AttributeSet attrs) {
    16         super(context, attrs);
    17     }
    18 
    19     @Override
    20     public void beforeLogicLoop() {
    21 
    22     }
    23 
    24     @Override
    25     public RainItem getItem(int width, int height, Resources resources) {
    26         return new RainItem(width,height,resources); /** 要造的雨,是什么雨就在这里传入 */
    27     }
    28 
    29     @Override
    30     public int getCount() { /** 要制作的雨数目 */
    31         return 160;
    32     }
    33 }

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

     1 /**
     2  * Created by LinGuanHong on 2017/1/15.
     3  */
     4 
     5 public class RainItem extends BaseItem {
     6 
     7     private float opt;
     8     private int sizeX,sizeY; /** 充当角度 */
     9     private int startX,startY,stopX,stopY;
    10     private Paint paint;
    11     private Random random;
    12 
    13     public RainItem(int width, int height, Resources resources) {
    14         super(width,height,resources);
    15         init();
    16         loopInit();
    17     }
    18 
    19     @Override
    20     public void move() {
    21         startX += sizeX * opt;
    22         stopX  += sizeX * opt;
    23 
    24         startY += sizeY * opt;
    25         stopY  += sizeY * opt;
    26         if(startY > height){
    27             loopInit();
    28         }
    29     }
    30 
    31     @Override
    32     public void draw(Canvas canvas) {
    33         Log.d("zzzzz","drawView "+startX+" "+startY+" "+stopX+" "+stopY);
    34         canvas.drawLine(startX,startY,stopX,stopY,paint);
    35     }
    36 
    37     private void loopInit(){
    38         sizeX = 1  + random.nextInt(10);
    39         sizeY = 10 + random.nextInt(20);
    40 
    41         startX = random.nextInt(width );
    42         startY = random.nextInt(height);
    43 
    44         opt = 0.2f + random.nextFloat();
    45 
    46         stopX = startX + sizeX;
    47         stopY = startY + sizeY;
    48     }
    49 
    50     private void init(){
    51         paint = new Paint(Paint.ANTI_ALIAS_FLAG); /** 抗锯齿  */
    52         paint.setColor(0xffffffff); /** a,r,g,b 255,255,255,255 */
    53 
    54         random = new Random();
    55     }
    56 
    57 }

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

    开源地址

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

      

  • 相关阅读:
    tcp传送报文
    整理下本周工作中遇到的疑问;uid/euid/suid;docker镜像管理
    网络隔离
    ubuntu 只有客人会话登录(第一次深刻感受文件权限的威力 )
    ubuntu 只有客人会话登录(第一次深刻感受文件权限的威力)
    使用gdb查看栈帧的情况,有ebp
    使用gdb查看栈帧的情况, 没有ebp
    再看perf是如何通过dwarf处理栈帧的
    dwarf是如何处理栈帧的?
    数据库设计的误区—>CHAR与VARCHAR
  • 原文地址:https://www.cnblogs.com/linguanh/p/6342099.html
Copyright © 2011-2022 走看看