文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Android实现字母雨的效果

2022-06-06 07:59

关注

首先来看效果:

一、实现原理

在实现过程中,主要考虑整个界面由若干个字母组成的子母线条组成,这样的话把固定数量的字母封装成一个字母线条,而每个字母又封装成一个对象,这样的话,就形成了如下组成效果:

字母对象--》字母线条对象--》界面效果

每个字母都应该知道自己的位置坐标,自己上面的字母、以及自己的透明度:


class HackCode{
     Point p = new Point();//每一个字母的坐标
     int alpha = 255;//透明度值 默认255
     String code = "A";//字母的值
  }

而每个子母线条对象都有自己这条线条的初始底部起点,内部的多个字母都是根据线条的初始底部起点依次排列,包含多个字母对象集合,以及这条线条的唯一标示:


class HackLine{
  public int NUM = 0;//用于记录这列的标示
  private Point p = new Point();//线的初始位置
  List<HackCode> hcs = new ArrayList<HackView.HackCode>();//黑客字母的一条线
  }

在初始化的时候创建所有子母线条对象以及字母对象存入集合中:


@Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    mWidth = getMeasuredWidth();//获取控件宽高
    mHeight = getMeasuredHeight();
    mHackLines.clear();//清空集合
    initPlayData();//初始化播放数据
  }
  
  public void initPlayData(){
    initHackLine(mWidth/9, mHeight/12);
    initHackLine(mWidth/9, mHeight/7);
    HackLine hl;
    for (int i = 3; i < 9; i++) {
      hl= new HackLine();
      hl.p.x = mWidth/9*(i+1);
      hl.p.y = mHeight/7*(9-i);
      for (int j = 0; j < 7; j++) {
        HackCode hc = new HackCode();
        hc.alpha -= 30*j;
        hc.code = CODES[new Random().nextInt(CODES.length)];
        hc.p.x = hl.p.x;
        hc.p.y = hl.p.y-dip2px(getContext(), 25)*j;
        hl.hcs.add(hc);
      }
      mHackLines.add(hl);
      hl.NUM = mHackLines.size();
    }
  }

然后在

onDraw
方法中绘制:


@Override
protected void onDraw(Canvas canvas) {
  for (int i = 0; i < mHackLines.size(); i++) {
    drawText(i, canvas);
  }
  mHandler.sendEmptyMessageDelayed(WHAT, 100);//用于开启循环 线条滚动
  }
public void drawText(int nindex,Canvas canvas){
    HackLine hackLine = mHackLines.get(nindex);
    for (int i = 0; i < hackLine.hcs.size(); i++) {
      HackCode hackCode = hackLine.hcs.get(i);
      mPaint.setAlpha(hackCode.alpha);
      canvas.drawText(hackCode.code, hackCode.p.x, hackCode.p.y, mPaint);
    }
  }

接下来要滚动显示由

Handler
发送一个延时100毫秒的消息开始:


class WeakHandler extends Handler{
    WeakReference<Activity> mActivity; 
    public WeakHandler(Activity activity){
      mActivity = new WeakReference<Activity>(activity);
    }
    @Override
    public void handleMessage(Message msg) {
      if(mActivity.get() != null){
        switch (msg.what) {
        case WHAT:
          nextPlay(dip2px(getContext(), 20));
          for (int i = 0; i < mHackLines.size(); i++) {
            if(mHackLines.get(i).p.y >= mHeight/2*3){
              addHackLine(mHackLines.get(i));
            }
          }
          invalidate();
          break;
        }
      }
    }
  }

让整个线条往下走其实也就只用将线条的底部初始值Y坐标不断增加,内部字母随之更新位置就可以了:



  public void nextPlay(int Nnum){
    for (int i = 0; i < mHackLines.size(); i++) {
      List<HackCode> hcs = mHackLines.get(i).hcs;
      hcs.clear();
      mHackLines.get(i).p.y+=Nnum;
      for (int j = 0; j < 7; j++) {
        HackCode hc = new HackCode();
        hc.alpha -= 30*j;
        hc.code = CODES[new Random().nextInt(CODES.length)];
        hc.p.x = mHackLines.get(i).p.x;
        hc.p.y = mHackLines.get(i).p.y-dip2px(getContext(), 25)*j;
        hcs.add(hc);
      }
    }
  }

之后我们要考虑在合适的时间移除掉不需要的字母线条并增加新的子母线条,这里我是判断如果线条底部超过屏幕高度的一半时就移除当前线条并根据唯一标示添加新的线条:


  
  public void addHackLine(HackLine hackLine){
      if(hackLine == null){
        return;
      }
      int num = hackLine.NUM;
      mHackLines.remove(hackLine);//如果存在 删除  重新添加
      HackLine hl;
      hl= new HackLine();
      hl.p.x = mWidth/9*(num-1);
      hl.p.y = mHeight/12*(7-(num-1));
      for (int j = 0; j < 7; j++) {
        HackCode hc = new HackCode();
        hc.alpha -= 30*j;
        hc.code = CODES[new Random().nextInt(CODES.length)];
        hc.p.x = hl.p.x;
        hc.p.y = hl.p.y-dip2px(getContext(), 25)*j;
        hl.hcs.add(hc);
      }
      hl.NUM = num;
      mHackLines.add(hl);
  }

最后,在控件移除屏幕的时候终止消息循环,运行时记得将根布局设置背景为黑色:


@Override
  protected void onDetachedFromWindow() {
    super.onDetachedFromWindow();
    mHandler.removeCallbacksAndMessages(null);//停止刷新
  }

OKOK,字母雨已经出来啦~~ 思路清晰之后还是很简单的哦~

二、实现代码

整个代码也不算很长,就直接贴上了:



public class HackView extends View {
  
  private Paint mPaint;
  
  private int mWidth;
  
  private int mHeight;
  
  private static final String[] CODES = {
    "A","B","C","D","E","F","G","H","I","J","K",
    "L","M","N","O","P","Q","R","S","T","U","V",
    "W","K","Y","Z"
  };
  private static final int WHAT = 1;
  
  private List<HackLine> mHackLines = new ArrayList<HackView.HackLine>();
  private WeakHandler mHandler;
  public HackView(Context context) {
    this(context,null);
  }
  public HackView(Context context, AttributeSet attrs) {
    this(context, attrs,0);
  }
  public HackView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    init();
    mHandler = new WeakHandler((Activity) context);
  }
  class WeakHandler extends Handler{
    WeakReference<Activity> mActivity; 
    public WeakHandler(Activity activity){
      mActivity = new WeakReference<Activity>(activity);
    }
    @Override
    public void handleMessage(Message msg) {
      if(mActivity.get() != null){
        switch (msg.what) {
        case WHAT:
          nextPlay(dip2px(getContext(), 20));
          for (int i = 0; i < mHackLines.size(); i++) {
            if(mHackLines.get(i).p.y >= mHeight/2*3){
              addHackLine(mHackLines.get(i));
            }
          }
          invalidate();
          break;
        }
      }
    }
  }
  private void init() {
    mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    mPaint.setColor(Color.WHITE);
    mPaint.setTextSize(dip2px(getContext(), 20));
    mPaint.setStrokeCap(Cap.ROUND);
    mPaint.setStrokeWidth(dip2px(getContext(), 5));
    setLayerType(View.LAYER_TYPE_SOFTWARE, null);
  }
  @Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    mWidth = getMeasuredWidth();//获取控件宽高
    mHeight = getMeasuredHeight();
    mHackLines.clear();//清空集合
    initPlayData();
  }
  
  public void nextPlay(int Nnum){
    for (int i = 0; i < mHackLines.size(); i++) {
      List<HackCode> hcs = mHackLines.get(i).hcs;
      hcs.clear();
      mHackLines.get(i).p.y+=Nnum;
      for (int j = 0; j < 7; j++) {
        HackCode hc = new HackCode();
        hc.alpha -= 30*j;
        hc.code = CODES[new Random().nextInt(CODES.length)];
        hc.p.x = mHackLines.get(i).p.x;
        hc.p.y = mHackLines.get(i).p.y-dip2px(getContext(), 25)*j;
        hcs.add(hc);
      }
    }
  }
  
  public void addHackLine(HackLine hackLine){
      if(hackLine == null){
        return;
      }
      int num = hackLine.NUM;
      mHackLines.remove(hackLine);//如果存在 删除  重新添加
      HackLine hl;
      hl= new HackLine();
      hl.p.x = mWidth/9*(num-1);
      hl.p.y = mHeight/12*(7-(num-1));
      for (int j = 0; j < 7; j++) {
        HackCode hc = new HackCode();
        hc.alpha -= 30*j;
        hc.code = CODES[new Random().nextInt(CODES.length)];
        hc.p.x = hl.p.x;
        hc.p.y = hl.p.y-dip2px(getContext(), 25)*j;
        hl.hcs.add(hc);
      }
      hl.NUM = num;
      mHackLines.add(hl);
  }
  
  public void initHackLine(int x,int y){
    HackLine hl;
    for (int i = 0; i < 9; i++) {
      hl= new HackLine();
      hl.p.x = x*i;
      hl.p.y = y*(7-i);
      for (int j = 0; j < 7; j++) {
        HackCode hc = new HackCode();
        hc.alpha -= 30*j;
        hc.code = CODES[new Random().nextInt(CODES.length)];
        hc.p.x = hl.p.x;
        hc.p.y = hl.p.y-dip2px(getContext(), 25)*j;
        hl.hcs.add(hc);
      }
      mHackLines.add(hl);
      hl.NUM = mHackLines.size();
    }
  }
  
  public void initPlayData(){
    initHackLine(mWidth/9, mHeight/12);
    initHackLine(mWidth/9, mHeight/7);
    HackLine hl;
    for (int i = 3; i < 9; i++) {
      hl= new HackLine();
      hl.p.x = mWidth/9*(i+1);
      hl.p.y = mHeight/7*(9-i);
      for (int j = 0; j < 7; j++) {
        HackCode hc = new HackCode();
        hc.alpha -= 30*j;
        hc.code = CODES[new Random().nextInt(CODES.length)];
        hc.p.x = hl.p.x;
        hc.p.y = hl.p.y-dip2px(getContext(), 25)*j;
        hl.hcs.add(hc);
      }
      mHackLines.add(hl);
      hl.NUM = mHackLines.size();
    }
  }
  @Override
  protected void onDraw(Canvas canvas) {
    for (int i = 0; i < mHackLines.size(); i++) {
      drawText(i, canvas);
    }
    mHandler.sendEmptyMessageDelayed(WHAT, 100);
  }
  public void drawText(int nindex,Canvas canvas){
    HackLine hackLine = mHackLines.get(nindex);
    for (int i = 0; i < hackLine.hcs.size(); i++) {
      HackCode hackCode = hackLine.hcs.get(i);
      mPaint.setAlpha(hackCode.alpha);
      canvas.drawText(hackCode.code, hackCode.p.x, hackCode.p.y, mPaint);
    }
  }
  
  class HackLine{
    public int NUM = 0;//用于记录这列的标示
    private Point p = new Point();//线的初始位置
    List<HackCode> hcs = new ArrayList<HackView.HackCode>();//黑客字母的一条线
  }
  
  class HackCode{
     Point p = new Point();//每一个字母的坐标
     int alpha = 255;//透明度值 默认255
     String code = "A";//字母的值
  }
  @Override
  protected void onDetachedFromWindow() {
    super.onDetachedFromWindow();
    mHandler.removeCallbacksAndMessages(null);//停止刷新
  }
    
  public static int dip2px(Context context, float dpValue) { 
    final float scale = context.getResources().getDisplayMetrics().density; 
    return (int) (dpValue * scale + 0.5f); 
  } 
}

xml:


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:tools="http://schemas.android.com/tools"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:background="#000"
  tools:context=".MainActivity" >
  <com.zk.hack.HackView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    />
</RelativeLayout>

以上就是基于Android实现字母雨的效果全部内容,效果很好,有需要的小伙伴们可以参考学习。

您可能感兴趣的文章:Android营造雪花和雨滴浪漫效果Android实现粒子雨效果Android中View的炸裂特效实现方法详解Android仿QQ聊天撒花特效 很真实


阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-移动开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯