欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android實現(xiàn)字母雨的效果

 更新時間:2016年07月26日 11:58:39   投稿:daisy  
在學(xué)習(xí)Android的時候見到別人實現(xiàn)的黑客帝國的字母雨效果,感覺效果很炫,今天我們也來實現(xiàn)一下。

首先來看效果:

一、實現(xiàn)原理

在實現(xiàn)過程中,主要考慮整個界面由若干個字母組成的子母線條組成,這樣的話把固定數(shù)量的字母封裝成一個字母線條,而每個字母又封裝成一個對象,這樣的話,就形成了如下組成效果:

字母對象--》字母線條對象--》界面效果

每個字母都應(yīng)該知道自己的位置坐標(biāo),自己上面的字母、以及自己的透明度:

class HackCode{
     Point p = new Point();//每一個字母的坐標(biāo)
     int alpha = 255;//透明度值 默認(rèn)255
     String code = "A";//字母的值
  }

而每個子母線條對象都有自己這條線條的初始底部起點,內(nèi)部的多個字母都是根據(jù)線條的初始底部起點依次排列,包含多個字母對象集合,以及這條線條的唯一標(biāo)示:

class HackLine{
  public int NUM = 0;//用于記錄這列的標(biāo)示
  private Point p = new Point();//線的初始位置
  List<HackCode> hcs = new ArrayList<HackView.HackCode>();//黑客字母的一條線
  }

在初始化的時候創(chuàng)建所有子母線條對象以及字母對象存入集合中:

@Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);

    mWidth = getMeasuredWidth();//獲取控件寬高
    mHeight = getMeasuredHeight();
    mHackLines.clear();//清空集合
    initPlayData();//初始化播放數(shù)據(jù)
  }

  /**
   * 初始化播放數(shù)據(jù)
   */
  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);//用于開啟循環(huán) 線條滾動
  }

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發(fā)送一個延時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坐標(biāo)不斷增加,內(nèi)部字母隨之更新位置就可以了:

/**
   * 下一幀播放
   * @param Nnum 每次下移多遠(yuǎn) 距離
   */
  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);
      }
    }
  }

之后我們要考慮在合適的時間移除掉不需要的字母線條并增加新的子母線條,這里我是判斷如果線條底部超過屏幕高度的一半時就移除當(dāng)前線條并根據(jù)唯一標(biāo)示添加新的線條:

  /**
   * 刪除一列 同時添加初始化一列
   * @param hackLine 
   */
  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);
  }

最后,在控件移除屏幕的時候終止消息循環(huán),運(yùn)行時記得將根布局設(shè)置背景為黑色:

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

OKOK,字母雨已經(jīng)出來啦~~ 思路清晰之后還是很簡單的哦~

二、實現(xiàn)代碼

整個代碼也不算很長,就直接貼上了:

/**
 * 字母雨
 * @author zhang
 *
 */
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;
  /** 所有的HackLine組合 */
  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();
  }
  /**
   * 下一幀播放
   * @param Nnum 每次下移多遠(yuǎn) 距離
   */
  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);
      }
    }
  }
  /**
   * 刪除一列 同時添加初始化一列
   * @param hackLine 
   */
  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);
  }
  /**
   * 初始化每一行數(shù)據(jù)
   * @param x
   * @param y
   */
  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();
    }
  }
  /**
   * 初始化播放數(shù)據(jù)
   */
  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;//用于記錄這列的標(biāo)示
    private Point p = new Point();//線的初始位置
    List<HackCode> hcs = new ArrayList<HackView.HackCode>();//黑客字母的一條線
  }
  /**
   * 每個字母
   */
  class HackCode{
     Point p = new Point();//每一個字母的坐標(biāo)
     int alpha = 255;//透明度值 默認(rèn)255
     String code = "A";//字母的值
  }
  @Override
  protected void onDetachedFromWindow() {
    super.onDetachedFromWindow();
    mHandler.removeCallbacksAndMessages(null);//停止刷新
  }
   /** 
   * 根據(jù)手機(jī)的分辨率從 dip 的單位 轉(zhuǎn)成為 px(像素) 
   */ 
  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實現(xiàn)字母雨的效果全部內(nèi)容,效果很好,有需要的小伙伴們可以參考學(xué)習(xí)。

相關(guān)文章

  • Android自定義View編寫隨機(jī)驗證碼

    Android自定義View編寫隨機(jī)驗證碼

    這篇文章主要為大家詳細(xì)介紹了Android自定義View隨機(jī)驗證碼實現(xiàn)代碼,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-10-10
  • Android開發(fā)常見問題總結(jié)

    Android開發(fā)常見問題總結(jié)

    這篇文章主要介紹了Android開發(fā)常見問題,總結(jié)分析了諸如界面設(shè)計、多媒體調(diào)用、圖片、動畫操作等開發(fā)中常見的問題解決方法與相關(guān)注意事項,需要的朋友可以參考下
    2016-08-08
  • Android使用Notification在狀態(tài)欄上顯示通知

    Android使用Notification在狀態(tài)欄上顯示通知

    這篇文章主要為大家詳細(xì)介紹了Android使用Notification在狀態(tài)欄上顯示通知,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-12-12
  • 詳解adb工具的基本使用

    詳解adb工具的基本使用

    adb全稱Android Debug Bridge,是Android SDK中的一個工具, 使用adb可以直接操作管理Android模擬器或者真實的Andriod設(shè)備,就是起到調(diào)試橋的作用,這篇文章主要介紹了adb工具的基本使用,需要的朋友可以參考下
    2022-08-08
  • Android網(wǎng)頁H5 Input選擇相機(jī)和系統(tǒng)相冊

    Android網(wǎng)頁H5 Input選擇相機(jī)和系統(tǒng)相冊

    這篇文章主要為大家詳細(xì)介紹了Android網(wǎng)頁H5 Input選擇相機(jī)和系統(tǒng)相冊,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-10-10
  • flutter Container容器實現(xiàn)圓角邊框

    flutter Container容器實現(xiàn)圓角邊框

    這篇文章主要為大家詳細(xì)介紹了flutter Container容器實現(xiàn)圓角邊框,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-07-07
  • Android 文件存儲與SharedPreferences存儲方式詳解用法

    Android 文件存儲與SharedPreferences存儲方式詳解用法

    SharedPreferences是安卓平臺上一個輕量級的存儲類,用來保存應(yīng)用的一些常用配置,比如Activity狀態(tài),Activity暫停時,將此activity的狀態(tài)保存到SharedPereferences中;當(dāng)Activity重載,系統(tǒng)回調(diào)方法onSaveInstanceState時,再從SharedPreferences中將值取出
    2021-10-10
  • Android ViewDragHelper實現(xiàn)京東、淘寶拖拽詳情功能的實現(xiàn)

    Android ViewDragHelper實現(xiàn)京東、淘寶拖拽詳情功能的實現(xiàn)

    這篇文章主要介紹了Android ViewDragHelper實現(xiàn)京東、淘寶拖拽詳情,實現(xiàn)這種效果大概分為三種方式,具體哪三種方式大家通過本文了解下吧
    2018-04-04
  • android文件上傳示例分享(android圖片上傳)

    android文件上傳示例分享(android圖片上傳)

    最近在做項目是用到Android上傳功能,就寫了個Android上傳組件,支持拍照錄用錄視頻和選擇文件,需要的朋友可以參考下
    2014-04-04
  • android實現(xiàn)菜單三級樹效果

    android實現(xiàn)菜單三級樹效果

    這篇文章主要為大家詳細(xì)介紹了android實現(xiàn)菜單三級樹效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-11-11

最新評論