Android自定義View做到彈幕效果

點擊上方「Android編程精選」,選擇「置頂公眾號」關鍵時刻,第一時間送達!

來源:Android開發中文站

https://mp.weixin.qq.com/s/l_UNrpHWLQrbBxPdJeaXUw

Android編程精整理髮布,轉載請聯繫作者獲得授權

在很多視頻直播中都有彈幕功能,而安卓上沒有簡單好用的彈幕控件,本文介紹一個自定義彈幕view的demo。

效果圖:

思路:

自定義Textitem類表示彈幕的信息

自定義view繼承view,使用ArrayList保存每條Textitem

隨機生成坐標點繪制每條TextItem,不斷變換Text的橫坐標做到彈幕的滾動

首先創建彈幕類,彈幕包括坐標,顏色,滾動速度,以及文字內容:

publicclassTextitem{privateStringcontent;privatefloatfx;privatefloatfy;privatefloatperstep;privateinttextcolor;publicTextitem(Stringcontent,floatfx,floatfy,floatperstep,inttextcolor){this.content=content;this.fx=fx;this.fy=fy;this.perstep=perstep;this.textcolor=textcolor;}publicStringgetContent(){returncontent;}publicvoidsetContent(Stringcontent){this.content=content;}publicintgetTextcolor(){returntextcolor;}publicvoidsetTextcolor(inttextcolor){this.textcolor=textcolor;}publicfloatgetFx(){returnfx;}publicvoidsetFx(floatfx){this.fx=fx;}publicfloatgetFy(){returnfy;}publicvoidsetFy(floatfy){this.fy=fy;}publicfloatgetPerstep(){returnperstep;}publicvoidsetPerstep(){fx-=perstep;}}

接下來自定義View,彈幕橫坐標不斷變換,需要做到定時刷新界面,重新繪制text。所以做到了Runable接口,在構造方法中開啟線程,不斷循環,每600毫秒刷新界面:

publicclassbarrageviewextendsViewimplementsRunnable{privateList<Textitem>items=newArrayList<>();Randomrandom=newRandom();privatePaintpaint;publicbarrageview(Contextcontext){super(context);initpaint();newThread(this).start();}publicbarrageview(Contextcontext,AttributeSetattrs){super(context,attrs);initpaint();newThread(this).start();}publicbarrageview(Contextcontext,AttributeSetattrs,intdefStyleAttr){super(context,attrs,defStyleAttr);initpaint();newThread(this).start();}publicvoidaddTextitem(Stringcontent){floatx=random.nextFloat()*getWidth();floaty=Math.abs(random.nextFloat()*(getHeight()-50))+40;floatstep=random.nextFloat()*50;intr=random.nextInt(255);intg=random.nextInt(255);intb=random.nextInt(255);Textitemitem=newTextitem(content,x,y,step,Color.rgb(r,g,b));items.add(item);}publicvoidinitpaint(){paint=newTextPaint(Paint.ANTI_ALIAS_FLAG);paint.setColor(Color.RED);paint.setTextSize(30);}@Overridepublicvoiddraw(Canvascanvas){super.draw(canvas);for(Textitemitem:items){paint.setColor(item.getTextcolor());canvas.drawText(item.getContent(),item.getFx(),item.getFy(),paint);}}@Overridepublicvoidrun(){while(true){try{Thread.sleep(600);for(Textitemitem:items){item.setPerstep();}postInvalidate();}catch(InterruptedExceptione){e.printStackTrace();}}}}

彈幕VIew就是不斷從ArrayList中獲取彈幕進行繪制,由於在其他線程進行刷新,所以使用postInvalidate進行重繪。

由於只是做到demo,很多問題沒有考慮,存在問題:

彈幕離開螢幕後沒有進行清除,使得ArrayList不斷擴大,可以進行一個判斷,若Textitem的繪制區域不在螢幕內則刪掉此item

彈幕若沒有交互需求,可以使用Surfaceview進行繪制,SurfaceView可以在子線程更新UI,多緩存機制也可以避免畫面跳動

另外注意下自定義View的構造函數的調用時機:

publicView(Contextcontext)是在java代碼創建視圖直接通過new方法創建的時候被調用,publicView(Contextcontext,Attributesetattrs)是在xml創建但是沒有指定style的時候被調用publicView(ContextContext,AttributeSetattrs,intdefStyle)給View提供一個基本的style,沒有對View設置屬性就使用style中的屬性

【點擊成為Java大神】

[do_widget id=yuzo_widget-4] [do_widget id=yuzo_widget-9] 流行