android自定義View----文字部分漸變效果

今天做的是一個簡單支持文字部分漸變效果的控件,還是先放上成果:


loading

tab

如上圖牧氮,這個控件可以做特殊的loading動畫郭赐,比如下載更振、上傳、等斯嚎,也可以用在viewpager切換時的tab利虫,實現(xiàn)文字部分變色等。

  • 實現(xiàn)原理:

  • 拿到文字堡僻,先把它渲染在畫布上糠惫,作為底色

  • 然后對畫布進行矩形裁剪clipRect(),paint換一種顏色钉疫,再把文字繪制一遍硼讽,即可

  • 裁剪的尺寸是根據(jù)外部傳入的progress、漸變方向牲阁、以及文字的寬高確定

    • 先鋪代碼:

attrs.xml 比較簡單固阁,定義兩種對比的顏色、文字大小和文字內(nèi)容 :

<declare-styleable name="ShadeTextView">
        <attr name="text" format="string"/>
        <attr name="firstColor" format="color"/>
        <attr name="secondColor" format="color"/>
        <attr name="textSize" format="dimension"/>
    </declare-styleable>
  • 寫一個view的子類城菊,(其實繼承TextView更方便一點)

全局變量

    private int mDirection ; //漸變的方向

    public static final int DIRECTION_LEFT = 0;
    public static final int DIRECTION_RIGHT = 1;
    public static final int DIRECTION_TOP = 2;
    public static final int DIRECTION_BOTTOM = 3;

    public void setDirection(int direction) {
        mDirection = direction;
        postInvalidate();
    }

    private Paint mPaint;

    private String mText;//顯示的文字

    private int mTextSize;//文字大小

    private float mProgress;//漸變位置

    private int mFirstColor;//base文字顏色

    private int mSecondColor;//變化的文字顏色

    public void setmProgress(float mProgress) {
        this.mProgress = mProgress;
        postInvalidate();
    }

構(gòu)造器,我的千篇一律的寫法~~

    public ShadeTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs, R.styleable.ShadeTextView, 0, defStyleAttr);

        for (int i = 0; i < typedArray.length(); i++) {
            int attr = typedArray.getIndex(i);
            switch (attr) {
                case R.styleable.ShadeTextView_text:
                    mText = typedArray.getString(attr);
                    break;
                case R.styleable.ShadeTextView_firstColor:
                    mFirstColor = typedArray.getColor(attr, Color.BLACK);
                    break;
                case R.styleable.ShadeTextView_secondColor:
                    mSecondColor = typedArray.getColor(attr, Color.BLUE);
                    break;
                case R.styleable.ShadeTextView_textSize:
                    mTextSize = typedArray.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(
                            TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics()));
                    break;
                /*case R.styleable.ShadeTextView_progress:
                    mProgress = typedArray.getInteger(attr, 30);
                    break;*/
            }
        }
        typedArray.recycle();
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setTextSize(mTextSize);
    }

onMeasure()的處理,如果繼承TextView的話可以省略很多代碼备燃。。凌唬。

@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int specMode = MeasureSpec.getMode(widthMeasureSpec);
        int specSize = MeasureSpec.getSize(widthMeasureSpec);

        int width = 0, height = 0;

        switch (specMode) {
            case MeasureSpec.EXACTLY:
                width = specSize + getPaddingRight() + getPaddingLeft();
                break;

            case MeasureSpec.AT_MOST:
                width = (int) (mPaint.measureText(mText) + getPaddingLeft() + getPaddingRight());//先確定mPaint是否已經(jīng)設置textsize
                break;
        }

        specMode = MeasureSpec.getMode(heightMeasureSpec);
        specSize = MeasureSpec.getSize(heightMeasureSpec);
        switch (specMode) {
            case MeasureSpec.EXACTLY:
                height = specSize + getPaddingTop() + getPaddingBottom();
                break;
            case MeasureSpec.AT_MOST:
                height = (int) (Math.abs(mPaint.getFontMetrics().bottom - mPaint.getFontMetrics().top) + getPaddingTop() + getPaddingBottom());
                break;
        }

        setMeasuredDimension(width, height);

    }

重頭戲 onDraw()赚爵,本篇的思想精華所在。

    @Override
    protected void onDraw(Canvas canvas) {
        float textWidth = mPaint.measureText(mText);
        float mLeft = (getMeasuredWidth() - textWidth) / 2;
        float textHeight = Math.abs(mPaint.getFontMetrics().bottom - mPaint.getFontMetrics().top);
        float mTop = (getMeasuredHeight() - textHeight) /2 ;

        //先畫底層的文字
        mPaint.setColor(mFirstColor);
        canvas.drawText(mText, mLeft, getY(), mPaint);
      
        mPaint.setColor(mSecondColor);
        // 接著根據(jù)傳入的漸變方向、顏色等來裁剪冀膝,接著在同樣的位置重新渲染文字
        if (mDirection == DIRECTION_LEFT) {
            canvas.save(Canvas.CLIP_SAVE_FLAG);
            canvas.clipRect(mLeft, 0, textWidth * mProgress + mLeft, getMeasuredHeight());
            canvas.drawText(mText, mLeft, getY(), mPaint);
            canvas.restore();
        } else if (mDirection == DIRECTION_RIGHT){
            canvas.save(Canvas.CLIP_SAVE_FLAG);
            canvas.clipRect(textWidth - textWidth * mProgress + mLeft , 0 , textWidth + mLeft, getMeasuredHeight());
            canvas.drawText(mText, + mLeft, getY(), mPaint);
            canvas.restore();
        } else if (mDirection == DIRECTION_TOP){
            canvas.save(Canvas.CLIP_SAVE_FLAG);
            canvas.clipRect(0, mTop , getWidth(), textHeight * mProgress + mTop);
            canvas.drawText(mText, + mLeft, getY(), mPaint);
            canvas.restore();
        }else if (mDirection == DIRECTION_BOTTOM){
            canvas.save(Canvas.CLIP_SAVE_FLAG);
            canvas.clipRect(0, textHeight - textHeight * mProgress + mTop, getWidth(), textHeight + mTop );
            canvas.drawText(mText, + mLeft, getY(), mPaint);
            canvas.restore();
        }
    }
    public float getY() {
        Paint.FontMetricsInt fm = mPaint.getFontMetricsInt();
        return (getHeight() + fm.descent - fm.ascent) / 2 - fm.descent;
    }

值得說明的是,
float textHeight = Math.abs(mPaint.getFontMetrics().bottom - mPaint.getFontMetrics().top);
return (getHeight() + fm.descent - fm.ascent) / 2 - fm.descent;
這里借鑒了Android 自定義View-怎么繪制居中文本霎挟?的研究成果窝剖,怒學。

  • View基本寫完酥夭,可以先測試了赐纱,先用seekbar測試四個方向的漸變效果,代碼比較簡單熬北,只貼一段根據(jù)seekbar的progress值設置我們自定義View的漸變方向和漸變位置的代碼:

 @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                shadeTextView.setDirection(ShadeTextView.DIRECTION_TOP);
                shadeTextView.setmProgress(progress * 1.0f / 100);
            }

運行測試疙描,基本OK


運用到viewpager中的代碼也比較簡單,只貼核心調(diào)用部分讶隐,其他大家都很熟悉了起胰。

@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
       if (positionOffset > 0){

            ShadeTextView left = shadeTextViews.get(position);
            ShadeTextView right = shadeTextViews.get(position + 1);

            left.setDirection(1);
            right.setDirection(0);

            left.setmProgress(1-positionOffset);
            right.setmProgress(positionOffset);
      }
}

然后效果就是文首的viewpager切換效果了。

源碼點擊查看

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末巫延,一起剝皮案震驚了整個濱河市效五,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌炉峰,老刑警劉巖畏妖,帶你破解...
    沈念sama閱讀 217,185評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異疼阔,居然都是意外死亡戒劫,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評論 3 393
  • 文/潘曉璐 我一進店門婆廊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來迅细,“玉大人,你說我怎么就攤上這事否彩》柙埽” “怎么了?”我有些...
    開封第一講書人閱讀 163,524評論 0 353
  • 文/不壞的土叔 我叫張陵列荔,是天一觀的道長敬尺。 經(jīng)常有香客問我,道長贴浙,這世上最難降的妖魔是什么砂吞? 我笑而不...
    開封第一講書人閱讀 58,339評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮崎溃,結(jié)果婚禮上蜻直,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好概而,可當我...
    茶點故事閱讀 67,387評論 6 391
  • 文/花漫 我一把揭開白布呼巷。 她就那樣靜靜地躺著,像睡著了一般赎瑰。 火紅的嫁衣襯著肌膚如雪王悍。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,287評論 1 301
  • 那天餐曼,我揣著相機與錄音压储,去河邊找鬼。 笑死源譬,一個胖子當著我的面吹牛集惋,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播踩娘,決...
    沈念sama閱讀 40,130評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼刮刑,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了霸饲?” 一聲冷哼從身側(cè)響起为朋,我...
    開封第一講書人閱讀 38,985評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎厚脉,沒想到半個月后习寸,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,420評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡傻工,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,617評論 3 334
  • 正文 我和宋清朗相戀三年霞溪,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片中捆。...
    茶點故事閱讀 39,779評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡鸯匹,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出泄伪,到底是詐尸還是另有隱情殴蓬,我是刑警寧澤,帶...
    沈念sama閱讀 35,477評論 5 345
  • 正文 年R本政府宣布蟋滴,位于F島的核電站染厅,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏津函。R本人自食惡果不足惜肖粮,卻給世界環(huán)境...
    茶點故事閱讀 41,088評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望尔苦。 院中可真熱鬧涩馆,春花似錦行施、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至涯雅,卻和暖如春须教,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背斩芭。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留乐疆,地道東北人划乖。 一個月前我還...
    沈念sama閱讀 47,876評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像挤土,于是被迫代替她去往敵國和親琴庵。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,700評論 2 354

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

  • 1: 獲取控件寬高 控件View有getHeight()和getwidth()方法可以獲取寬高仰美,但是如果直接在on...
    自由人是工程師閱讀 1,778評論 0 0
  • 效果圖如下: 一迷殿。view的組成 看到上圖效果,大概可以確定這個view由三部分組成 1.繞一圈的正方形 2.中間...
    小鄭閱讀 391評論 0 0
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,098評論 25 707
  • ……即使是明顯愛孩子的家長也不能永遠做到行為上尊重孩子……他們無視孩子的要求咖杂、怠慢孩子生氣時的感受庆寺、輕視孩子的恐懼...
    球爸小新閱讀 304評論 0 1
  • 每個人都有自己的歸宿,干著自己的喜歡而且收入不錯的工作诉字,暇時去過過夜生活懦尝,不浮夸,也不過度小資壤圃,平靜而又熱情陵霉。然而...
    午夜的星星閱讀 181評論 0 0