一篇文字跳動控制元件,為你開啟一扇大門,學會這兩點心得,控制元件你也會寫
做開發已經3年有餘了,一事無成,一直靜不下心來安心做好一件事情,很多時候內心很浮躁,迷失了前行的方向,我該當何去何從?一個人閒下來的時候,總想放縱自己,二個人在一起總會吵吵鬧鬧,在物質驅使的年代裡,活得一點不像自己,像我這樣的人,還有多少人?
心裡的話一直想找人說,讓大家見笑了。本篇是講技術的,而不是來聽我的感慨。希望看完本篇能對你 自定義控制元件 有所幫助,大牛大神級別的人物可以繞過。先看看效果圖,圖文並茂,有助於文章的理解:

跳動文字控制元件
據群裡很大一部分童鞋反應,覺得寫 自定義控制元件 好難,害怕去寫。那我談談自己的心得,有兩點:
-
第一,拆分
-
第二,模仿
在平面(2D)動畫中我們一般只考慮橫縱座標,那麼就可以拆分為 x
和 y
方向的動畫,動畫無非就是平移,旋轉,縮放以及透明度變換中的一種或者幾種,化繁為簡。
騰訊,小米一直在模仿,一直很成功,那麼寫控制元件一樣,也需要模仿,尤其對於初學者,更需要模仿。先不論你寫的控制元件是不是最優方案,效能是否有過渡損耗,動手模仿寫一寫,可以找些簡單例子練練手,強力推薦 ofollow,noindex">啟艦大牛 ,寫的很細很全面。
看到這裡,你有信心寫好上方 跳動文字控制元件 嗎?如果是你拿到這個控制元件需求,很想聽聽大家的分析思路,歡迎留言?很多時候實現方案往往不會是一種,你的答案,可能對他人有所幫助,接下來具體講解 跳動文字控制元件 的實現。
跳動文字
需求分析,紅色字型的 wen
為已經繪製的文字(舊文字),白色的 tianxia
為即將繪製的文字(新文字),新舊文字相同的字元為 n
,針對新舊文字拆分 x,y
軸方向的動畫:
舊文字
n n
新文字
n

跳動文字控制元件
拆分後你會發現就只有簡單的平移與透明度動畫,是不是一下就覺得簡單了許多,先實現 舊文字 的動畫。
舊文字
在 x 軸方向字元 n
的平移動畫,根據數學公式( n
字元x座標 = 起點 + (終點 - 起點)x 進度),起點與終點分別對應舊新文字字元 n
所在的 x
軸座標,進度的取值範圍為[0~1];y 軸方向的平移與透明動畫就相對簡單,請參考程式碼理解。
獲取 n
字元x座標相關方法:
/** * 獲取舊文字字元n的x座標 * * @param from舊文字字元n的索引位置 * @param move新文字字元n的索引位置 * @param progress當前進度 * @param startX新文字baseline的x座標 * @param oldStartX 舊文字baseline的y座標 * @param gaps新文字每個字元對應的x座標集合 * @param oldGaps舊文字每個字元對應的x座標集合 * @return */ public static float getOffset(int from, int move, float progress, float startX, float oldStartX, List<Float> gaps, List<Float> oldGaps) { float dist = startX; for (int i = 0; i < move; i++) { dist += gaps.get(i); } float cur = oldStartX; for (int i = 0; i < from; i++) { cur += oldGaps.get(i); } return cur + (dist - cur) * progress; }
繪製舊文字相關程式碼,有不懂的地方,請留言或結合demo理解:
float startX = mHTextView.getLayout().getLineLeft(0); float startY = mHTextView.getBaseline(); float offset = startX; float oldOffset = oldStartX; int maxLength = Math.max(mText.length(), mOldText.length()); for (int i = 0; i < maxLength; i++) { // draw old text if (i < mOldText.length()) { // pp = progress; 0~1progress * duration / (charTime + charTime / mostCount * (mText.length() - 1)) float pp = progress; mOldPaint.setTextSize(mTextSize); int move = CharacterUtils.needMove(i, differentList); if (move != -1) { // 需要移動的字元 左右平移運動 視覺欺騙並沒有上下的運動 mOldPaint.setAlpha(255); // * 2f 平移速度 float p = pp * 2f; p = p > 1 ? 1 : p; float distX = CharacterUtils.getOffset(i, move, p, startX, oldStartX, gapList, oldGapList); canvas.drawText(mOldText.charAt(i) + "", 0, 1, distX, startY, mOldPaint); } else { //y軸方向的透明度動畫 mOldPaint.setAlpha((int) ((1 - pp) * 255)); //y軸方向的平移動畫 float y = startY - pp * mTextHeight; float width = mOldPaint.measureText(mOldText.charAt(i) + ""); // (oldGapList.get(i) - width) / 2 值為0oldOffset + (oldGapList.get(i) - width) / 2 canvas.drawText(mOldText.charAt(i) + "", 0, 1, oldOffset, y, mOldPaint); } oldOffset += oldGapList.get(i); } }
新文字
新文字只有簡單的平移,透明度動畫,相關程式碼如下:
if (i < mText.length()) { if (!CharacterUtils.stayHere(i, differentList)) { // 漸顯效果 延遲 int alpha = (int) (255f / charTime * (progress * duration - charTime * i / mostCount)); alpha = alpha > 255 ? 255 : alpha; alpha = alpha < 0 ? 0 : alpha; mPaint.setAlpha(alpha); mPaint.setTextSize(mTextSize); //float pp = progress * duration / (charTime + charTime / mostCount * (mText.length() - 1)); float pp = progress; // y方向的平移動畫 float y = mTextHeight + startY - pp * mTextHeight; float width = mPaint.measureText(mText.charAt(i) + ""); canvas.drawText(mText.charAt(i) + "", 0, 1, offset + (gapList.get(i) - width) / 2, y, mPaint); } offset += gapList.get(i); }
寫好控制元件在於分析與拆分,再複雜的動畫也是由簡單的動畫組合而成,先化繁為簡,後以簡組繁,多練多寫,沒有任何捷徑,自我覺得 “開發就像積累經驗一樣,開發越久,經驗越多,你就是老手。”
小編正在維護 MeiWidgetView 庫,有炫酷的控制元件可以推薦,萬分感謝,給小編一顆 star ,才是最好最美的回報。
參考地址: