Android中TextView文字鏤空效果的實現(xiàn)

最近在做需求的時候,設(shè)計小姐姐提了個效果巧骚,說需要TextView展示文字的時候要鏤空效果,也就是文字和背景相交的地方是透明的效果就像下邊這張圖
雖然我剛開始沒有什么思路,但是我可以google一下啊搔扁,于是我找到了一個實現(xiàn)的方式,效果也和預(yù)期的一樣蟋字,我參考的就是這篇文章介紹的android如何實現(xiàn)鏤空文字稿蹲,于是Android中TextView文字鏤空效果的實現(xiàn)就完成了,到此結(jié)束 謝謝大家的閱讀~

鏤空.jpg

開個玩笑鹊奖,這片文章的思路其實就是使用了PorterDuff.Mode的方式來混合圖片苛聘,如果對PorterDuff.Mode不熟悉的可以看下這篇文章各個擊破搞明白PorterDuff.Mode
我看了幾篇關(guān)于鏤空文字的文章,基本的思路都是如下:

  • 自定義了HolloTextView繼承自View
  • 重寫onDraw方法
  • 繪制背景
  • 使用PorterDuff.Mode.DST_OUT的畫筆調(diào)用canvas.drawText方法繪制文字

基本通過上面的方法就可做到了文字的鏤空效果忠聚,但是我覺得有兩點不太妥當?shù)牡胤剑?/p>

  • HolloTextView繼承的View设哗,如果原來xml使用的是TextView這樣替換的話如果代碼里的引用的對象沒有替換,容易造成崩潰
  • 因為是通過canvas的drawText方法繪制的文字两蟀,TextView原有的各種屬性全部都失效了网梢,textSize、textStyle赂毯、padding等等战虏,如果想實現(xiàn)這些屬性,需要自定義大量的屬性不是很方便

為了解決這兩個不方便的地方党涕,我想了一下解決的方法烦感,也是主要分為下面這幾步:

  • HollowTextView繼承自TextView
  • 自定義兩個Bitmap,一個用于繪制文字膛堤,一個用于繪制背景
  • 定義兩個Canvas手趣,分別在new的時候傳入上面兩個bitmap
  • 重寫onDraw方法繪制文字和背景

這里主要著重說一下這個onDraw方法是如何重寫的,既然我們想解決上面的第二個問題骑祟,那就需要我們能夠支持TextView的一些基本的屬性回懦,我們知道TextView的一些基本屬性最后都是在onDraw方法繪制出來的,那么我們能不能利用HollowTextView的super.onDraw(Canvas)方法把那些屬性保存下來呢次企?答案是可以的怯晕,這里我用了一個取巧的辦法,在onDraw里面調(diào)用super.onDraw(Canvas)時缸棵,傳入的Canvas是之前定義的傳入了TextBitmap的TextCanvas舟茶,這樣所有有關(guān)TextView的基本屬性就都繪制到了TextBitmap這個Bitmap上,然后我們在onDraw方法里可以先繪制背景,然后在使用PorterDuff.Mode.DST_OUT模式的Paint繪制TextBitmap吧凉,這樣就很輕松的實現(xiàn)了文字的鏤空效果
關(guān)于PorterDuff.Mode.DST_OUT的效果隧出,在我提到的那篇介紹的文章里有說明,我可以在這里引用一下

  • DST_OUT
    [Da * (1 - Sa), Dc * (1 - Sa)]阀捅,可以類比SRC_OUT , 在不相交的地方繪制目標圖像胀瞪,相交處根據(jù)源圖像alpha進行過濾,完全不透明處則完全過濾饲鄙,完全透明則不過濾

說這么多不如看一下代碼來的痛快凄诞,下面給出我實現(xiàn)的代碼:

public class HollowTextView extends AppCompatTextView{
  private Paint mTextPaint, mBackgroundPaint;
  private Bitmap mBackgroundBitmap,mTextBitmap;
  private Canvas mBackgroundCanvas,mTextCanvas;
  private RectF mBackgroundRect;
  private int mBackgroundColor;
  private int mCornerRadius;

  public HollowTextView(Context context) {
    this(context,null);
  }

  public HollowTextView(Context context, AttributeSet attrs) {
    this(context, attrs,-1);
  }

  public HollowTextView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    initAttrs(attrs,defStyleAttr);
    initPaint();
  }


  private void initAttrs(AttributeSet attrs,int defStyleAttr){
    if(attrs == null){
      return;
    }
    TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.HollowTextView, defStyleAttr, 0);
    mBackgroundColor = a.getColor(R.styleable.HollowTextView_background_color,Color.TRANSPARENT);
    mCornerRadius = a.getDimensionPixelOffset(R.styleable.HollowTextView_corner_radius,0);
    a.recycle();
  }

  /***
   * 初始化畫筆屬性
   */
  private void initPaint() {
    //畫文字的paint
    mTextPaint = new Paint();
    //這是鏤空的關(guān)鍵
    mTextPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
    mTextPaint.setAntiAlias(true);
    mBackgroundPaint = new Paint();
    mBackgroundPaint.setColor(mBackgroundColor);
    mBackgroundPaint.setAntiAlias(true);

  }

  @Override
  protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
    mBackgroundBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_4444);
    mBackgroundCanvas = new Canvas(mBackgroundBitmap);
    mTextBitmap = Bitmap.createBitmap(w,h,Bitmap.Config.ARGB_4444);
    mTextCanvas = new Canvas(mTextBitmap);
    mBackgroundRect = new RectF(0,0,getWidth(),getHeight());
  }

  @Override
  protected void onDraw(Canvas canvas) {
    //這里給super傳入的是mTextCanvas,把一些基本屬性都支持進去
    super.onDraw(mTextCanvas);
    drawBackground(mBackgroundCanvas);
    int sc;
    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ){
       sc = canvas.saveLayer(0,0,getMeasuredWidth(),getMeasuredHeight(),null);
    }else {
       sc = canvas.saveLayer(0,0,getMeasuredWidth(),getMeasuredHeight(),null,Canvas.ALL_SAVE_FLAG);
    }
    canvas.drawBitmap(mBackgroundBitmap,0,0,null);
    canvas.drawBitmap(mTextBitmap, 0, 0, mTextPaint);
    canvas.restoreToCount(sc);
  }

  private void drawBackground(Canvas canvas){
    if(mCornerRadius > 0){
      canvas.drawRoundRect(mBackgroundRect,mCornerRadius,mCornerRadius, mBackgroundPaint);
    }else {
      canvas.drawColor(mBackgroundColor);
    }
  }
}

這樣就實現(xiàn)了鏤空文字的效果忍级,什么粗體字啊帆谍、換字體啊、margin轴咱、padding的都不用我們再去考慮了汛蝙,但是我這里還有一個問題沒有想到好的解決辦法,就是TextView的backgroud屬性沒有辦法通過xml來支持朴肺,因為混合模式需要除了文字部分都要透明窖剑,而backgroud屬性會破壞這個規(guī)則,所以我這里自己定義了background_color屬性宇挫,希望有興趣的小伙伴可以思考一下這個問題然后交流一下~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末苛吱,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子器瘪,更是在濱河造成了極大的恐慌翠储,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,248評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件橡疼,死亡現(xiàn)場離奇詭異援所,居然都是意外死亡,警方通過查閱死者的電腦和手機欣除,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評論 2 381
  • 文/潘曉璐 我一進店門住拭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人历帚,你說我怎么就攤上這事滔岳。” “怎么了挽牢?”我有些...
    開封第一講書人閱讀 153,443評論 0 344
  • 文/不壞的土叔 我叫張陵谱煤,是天一觀的道長。 經(jīng)常有香客問我禽拔,道長刘离,這世上最難降的妖魔是什么室叉? 我笑而不...
    開封第一講書人閱讀 55,475評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮硫惕,結(jié)果婚禮上茧痕,老公的妹妹穿的比我還像新娘。我一直安慰自己恼除,他們只是感情好踪旷,可當我...
    茶點故事閱讀 64,458評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著缚柳,像睡著了一般埃脏。 火紅的嫁衣襯著肌膚如雪搪锣。 梳的紋絲不亂的頭發(fā)上秋忙,一...
    開封第一講書人閱讀 49,185評論 1 284
  • 那天,我揣著相機與錄音构舟,去河邊找鬼灰追。 笑死,一個胖子當著我的面吹牛狗超,可吹牛的內(nèi)容都是我干的弹澎。 我是一名探鬼主播,決...
    沈念sama閱讀 38,451評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼努咐,長吁一口氣:“原來是場噩夢啊……” “哼苦蒿!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起渗稍,我...
    開封第一講書人閱讀 37,112評論 0 261
  • 序言:老撾萬榮一對情侶失蹤佩迟,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后竿屹,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體报强,經(jīng)...
    沈念sama閱讀 43,609評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,083評論 2 325
  • 正文 我和宋清朗相戀三年拱燃,在試婚紗的時候發(fā)現(xiàn)自己被綠了秉溉。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,163評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡碗誉,死狀恐怖召嘶,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情哮缺,我是刑警寧澤弄跌,帶...
    沈念sama閱讀 33,803評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站蝴蜓,受9級特大地震影響碟绑,放射性物質(zhì)發(fā)生泄漏俺猿。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,357評論 3 307
  • 文/蒙蒙 一格仲、第九天 我趴在偏房一處隱蔽的房頂上張望押袍。 院中可真熱鬧,春花似錦凯肋、人聲如沸谊惭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽圈盔。三九已至,卻和暖如春悄雅,著一層夾襖步出監(jiān)牢的瞬間驱敲,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評論 1 261
  • 我被黑心中介騙來泰國打工宽闲, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留众眨,地道東北人。 一個月前我還...
    沈念sama閱讀 45,636評論 2 355
  • 正文 我出身青樓容诬,卻偏偏與公主長得像娩梨,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子览徒,可洞房花燭夜當晚...
    茶點故事閱讀 42,925評論 2 344

推薦閱讀更多精彩內(nèi)容