1. 程式人生 > >自定義底部導航欄圖示

自定義底部導航欄圖示

底部導航欄我門一般的實現方式就是 

RadioGroup 和RadioButton這種組合.但是這樣會有很多弊端.比如有個訊息提示.比如要隨時改變圖示

/**
 * Created by sdx on 2016/12/28.
 * 底部導航欄圖示
 */

public class TabView extends View {

    private String mText;
    private Bitmap mBitmap;
    private Bitmap mClickBitmap;
    /**
     * 字型的大小.預設是12
     */
    private float textSize = 12f;
    private Rect tvRect;
    private Paint tvPaint;
    private RectF ivRect;
    private int padding;
    private int ivWidth;
    private int color;
    private int msgCount;
    /**
     * 條目普通的顏色
     */
    private static final int normalColor = 0X999999;
    /**
     * 條目點選的顏色
     */
    private static final int clickColor = 0XEF6160;
    /**
     * 訊息的背景顏色(訊息的數字是白色)
     */
    private static final int msgColor = 0XEF6160;
    /**
     * 設定當前的條目是否是點選狀態
     */
    private boolean isClick = false;

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

    public TabView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public TabView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.TabView);
        int indexCount = typedArray.getIndexCount();
        for (int i = 0; i < indexCount; i++) {
            int index = typedArray.getIndex(i);
            switch (index) {
                case R.styleable.TabView_tab_text:
                    mText = typedArray.getString(index);
                    break;
                case R.styleable.TabView_tab_image:
                    BitmapDrawable mBitmapDraawable = (BitmapDrawable) typedArray.getDrawable(index);
                    mBitmap = mBitmapDraawable.getBitmap();
                    break;
                case R.styleable.TabView_tab_text_size:
                    textSize = typedArray.getDimension(index, 12);
                    break;
                case R.styleable.TabView_tab_click_image:
                    BitmapDrawable clickDrawable = (BitmapDrawable) typedArray.getDrawable(index);
                    mClickBitmap = clickDrawable.getBitmap();
                    break;
            }
        }
        typedArray.recycle();
        tvRect = new Rect();
        tvPaint = new Paint();
        reText();

    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        padding = UIUtils.dp2px(getContext(), 4);
        int width = getMeasuredWidth() - padding * 2;
        int height = getMeasuredHeight() - padding * 2 - tvRect.height();
        ivWidth = Math.min(width, height);
        int left = getMeasuredWidth() / 2 - ivWidth / 2;
        int top = (getMeasuredHeight() - tvRect.height() - ivWidth) / 2;
        ivRect = new RectF(left, top, left + ivWidth, top + ivWidth);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        if (isClick) {
            drawBitmap(canvas, mClickBitmap);
            color = clickColor;
        } else {
            drawBitmap(canvas, mBitmap);
            color = normalColor;
        }

        drawText(canvas);
        if (msgCount > 0) {
            drawMessage(canvas);
        }

    }


    /**
     * 繪製訊息
     *
     * @param canvas
     */
    private void drawMessage(Canvas canvas) {
        //數字畫筆內容大小等建立
        Paint textPaint = new Paint();
        Rect textRect = new Rect();
        String text = msgCount > 99 ? "99+" : msgCount + "";
        int size ;
        if (text.length() == 1) {
            size = UIUtils.dp2px(getContext(), 10);
        } else if (text.length() == 2) {
            size = UIUtils.dp2px(getContext(), 9);
        } else {
            size = UIUtils.dp2px(getContext(), 7);
        }

        textPaint.setColor(Color.WHITE);
        textPaint.setFakeBoldText(true);
        textPaint.setAntiAlias(true);
        textPaint.setTextSize(size);
        textPaint.setTypeface(Typeface.MONOSPACE);
        textPaint.getTextBounds(text, 0, text.length(), textRect);
        textPaint.setTextAlign(Paint.Align.CENTER);
        Paint.FontMetrics fontMetrics = textPaint.getFontMetrics();


        //畫圓
        int width = UIUtils.dp2px(getContext(), 17);
        Paint paint = new Paint();
        paint.setColor(msgColor);
        paint.setAlpha(255);
        paint.setStyle(Paint.Style.FILL);
        paint.setAntiAlias(true);
        RectF messageRectF = new RectF(ivRect.right - width / 2, ivRect.top, ivRect.right + width / 2, ivRect.top + width);
        canvas.drawOval(messageRectF, paint);
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER));
        textPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER));
        //畫數字
        float x = messageRectF.right - messageRectF.width() / 2f;
        float y = messageRectF.bottom - messageRectF.height() / 2f - fontMetrics.descent + (fontMetrics.descent - fontMetrics.ascent) / 2;
        canvas.drawText(text, x, y, textPaint);
    }


    private void drawBitmap(Canvas canvas, Bitmap bitmap) {
        Bitmap bitmapTem = Bitmap.createBitmap(getMeasuredWidth(), getMeasuredHeight(),
                Bitmap.Config.ARGB_8888);
        Canvas canvasTem = new Canvas(bitmapTem);
        Paint paint = new Paint();
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
        canvasTem.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG));
        canvasTem.drawOval(ivRect, paint);
        canvasTem.drawBitmap(bitmap, null, ivRect, paint);
        canvas.drawBitmap(bitmapTem, 0, 0, null);
    }

    private void drawText(Canvas canvas) {
        tvPaint.setColor(color);
        tvPaint.setAlpha(255);
        float x = getMeasuredWidth() / 2 - tvRect.width() / 2;
        float y = ivRect.bottom + tvRect.height();
        canvas.drawText(mText, x, y, tvPaint);
    }

    /**
     * 重繪
     */
    private void invalidateView() {
        if (Looper.getMainLooper() == Looper.myLooper()) {
            invalidate();
        } else {
            postInvalidate();
        }
    }


    public void setClick(boolean isClick) {
        this.isClick = isClick;
        invalidateView();
    }


    /**
     * 設定一個網路的地址.加載出來bitmap
     *
     * @param src
     */
    private String lastSrc;

    public void setSrc(String src) {
        if (src == null) return;
        //如果兩次傳進來的地址一樣.就沒必要重新繪製bitmap
        if (src.equals(lastSrc)) return;
        lastSrc = src;
        Observable.just(src).observeOn(Schedulers.io()).subscribe(new Action1<String>() {
            @Override
            public void call(String s) {
                try {
                    mBitmap = mClickBitmap = Picasso.with(getContext()).load(s).transform(new Transformation() {
                        @Override
                        public Bitmap transform(Bitmap source) {
                            int size = Math.min(source.getWidth(), source.getHeight());

                            int x = (source.getWidth() - size) / 2;
                            int y = (source.getHeight() - size) / 2;

                            Bitmap squaredBitmap = Bitmap.createBitmap(source, x, y, size, size);
                            if (squaredBitmap != source) {
                                source.recycle();
                            }

                            Bitmap bitmap = Bitmap.createBitmap(size, size, source.getConfig());

                            Canvas canvas = new Canvas(bitmap);
                            Paint paint = new Paint();
                            BitmapShader shader = new BitmapShader(squaredBitmap, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP);
                            paint.setShader(shader);
                            paint.setAntiAlias(true);

                            float r = size / 2f;
                            canvas.drawCircle(r, r, r, paint);

                            squaredBitmap.recycle();
                            return bitmap;
                        }

                        @Override
                        public String key() {
                            return "circleImageTransformation";
                        }
                    }).get();
                    invalidateView();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });
    }

    /**
     * 設定訊息的數量
     *
     * @param count 訊息的數量
     */
    public void setMessage(int count) {
        this.msgCount = count;
        invalidateView();
    }

    /**
     * 設定文字
     *
     * @param text tab的文字
     */
    public void setText(String text) {
        this.mText = text;
        reText();
        invalidateView();
    }

    private void reText() {
        tvPaint.setTextSize(textSize);
        tvPaint.getTextBounds(mText, 0, mText.length(), tvRect);
        tvPaint.setAntiAlias(true);
    }

    private final static String KEY_NORMAL = "key_normal";
    private final static String KEY_STATE = "key_state";

    @Override
    protected Parcelable onSaveInstanceState() {
        Bundle bundle = new Bundle();
        bundle.putBoolean(KEY_STATE, isClick);
        bundle.putParcelable(KEY_NORMAL, super.onSaveInstanceState());
        return bundle;
    }

    @Override
    protected void onRestoreInstanceState(Parcelable state) {
        if (state instanceof Bundle) {
            Bundle bundle = (Bundle) state;
            isClick = bundle.getBoolean(KEY_STATE);
            super.onRestoreInstanceState(bundle.getParcelable(KEY_NORMAL));
        } else {
            super.onRestoreInstanceState(state);
        }
    }

    /**
     * 設定背景圖片
     *
     * @param normal 普通狀態的drawable
     * @param click  點選狀態的drawable
     */
    public void setImageView(final int normal, final int click) {
        Observable.just(normal).observeOn(Schedulers.io()).subscribe(new Action1<Integer>() {
            @Override
            public void call(Integer integer) {
                try {
                    mBitmap = Picasso.with(getContext()).load(normal).get();
                    mClickBitmap = Picasso.with(getContext()).load(click).get();
                    invalidateView();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
    }
}
<declare-styleable name="TabButton">
        <!--初始顯示的圖示-->
        <attr name="image" format="reference"/>
        <!--選中之後顯示的圖示-->
        <attr name="clickimage" format="reference"/>
        <!--選中之後顯示的顏色-->
        <attr name="clickcolor" format="color"/>
        <attr name="normalcolor" format="color"/>
        <!--圖示下顯示的文字,不要太長!-->
        <attr name="text" format="string"/>
        <!--文字的大小-->
        <attr name="text_size" format="dimension"/>
    </declare-styleable>

<com.ui.widgets.TabView
            android:id="@+id/tab_my"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            app:tab_click_image="@drawable/ic_tab_mine_s"
            app:tab_image="@drawable/ic_tab_mine_f"
            app:tab_text="我的"
            app:tab_text_size="12sp"
            />


因為專案裡邊用到了picasso和Rxjava所以這裡就直接用了.其實就是在子執行緒獲取到網路圖片的bitmap,然後繪製到view上;

參考: http://blog.csdn.net/tyzlmjj/article/details/47186249

相關推薦

定義底部導航圖示

底部導航欄我門一般的實現方式就是  RadioGroup 和RadioButton這種組合.但是這樣會有很多弊端.比如有個訊息提示.比如要隨時改變圖示 /** * Created by sdx on 2016/12/28. * 底部導航欄圖示 */ public

NavigationTabBar 定義底部導航

先來頁面效果 匯入依賴 implementation 'devlight.io:navigationtabbar:1.2.5' 先建立三個Fragment ,貼出其中一個Fragment 的程式碼  fragment_home.xml <?xml vers

android 定義底部導航

1.編寫佈局 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+

小程式定義底部導航樣式

1.微信app.json檔案中全域性配置小程式API "tabBar": { "color": "#fff", "selectedColor": "red", "backgroundColor": "skyblue", "list": [ { "pagePath": "pa

帶有指示器的定義底部導航的實現

  轉載請註明出處:http://blog.csdn.net/zhaokaiqiang1992     今天這篇文章,主要是給大家實現一個自定義的帶有指示器的底部導航欄。     先看一下實現的效果吧。   這個自定義控制元件的使用要注意以下幾個方面:    

vue定義底部導航Tabbar

如圖所示,要完成類似的一個底部導航切換。 首先。我們需要分為5個大的VUE檔案。可以根據自己的習慣來放在不同的位置。 我將5個主要的VUE檔案放在了5個不同的資料夾 然後,在元件資料夾裡新建Tabbar.vue /以及Item.vue檔案 Item.vue檔案

微信小程序-定義底部導航

tool vda www 程序 redirect pub otool lin 初始 代碼地址如下:http://www.demodashi.com/demo/14258.html 一、前期準備工作 軟件環境:微信開發者工具 官方下載地址:https://mp.weixi

React Native:定義一個導航,改變狀態列背景,隱藏狀態列

設計開發過程中,導航欄都會有所不同,這時候使用RN就需要自定義一個想要的導航欄了,RN中文網有講專門ios的導航欄(NavigatorIOS),可以不用自定義。 首先定義自定義導航欄的一些屬性的約束,記得npm install --save prop-types然後引入import Prop

微信小程式——定義底部導航樣式切換

1、以下截圖是靜態展示部分 解析: 1、catchtap='goHome' 是點選事件,點選的時候傳遞data-num='1',點選事件方法名都是一樣的,只是傳入的data-num值不同,通過這個不同的值,使用三元運算子來判斷需要顯示的樣式和圖示 2、圖示切換,通過

Recat Native:定義一個導航,改變狀態列背景,隱藏狀態列

設計開發過程中,導航欄都會有所不同,這時候使用RN就需要自定義一個想要的導航欄了,RN中文網有講專門ios的導航欄(NavigatorIOS),可以不用自定義。 首先定義自定義導航欄的一些屬性的約束,記得npm install --save prop-types然後引入im

小程式定義底部選單

   問題:小程式的底部選單欄基本的樣式根本不能滿足我們的審美要求,所以我們可以通過自己來自定義一套小程式底部欄,可以設定透明背景喲,想要什麼樣式都可以自己定義,好了,廢話不多說,直接上程式碼! 首先在和pages同一級建錄建立tabbar.xml,如右截圖所示 具體的t

微信小程式定義頂部導航,新增背景圖,透明色等.

在微信小程式中,導航欄的顏色可以在app.json.  window裡面新增navigationBarBackgroundColor屬性,但是顏色只能為純色.不能使用rgb,或者rgba的色號. 但是這

定義UINavigationController導航背景

方法一:自定義一個BaseNavigationViewController : UINavigationController 在初始化方法中加入以下程式碼,之後就使用BaseNavigationViewController [self.navigatio

微信小程式定義底部導航帶跳轉

index.wxml <!--底部導航 --> <view class='footer'> <view class='footer_list' data-id='{{

微信小程式-定義底部導航

之前我的做微信小程式的時候,需要一個底部導航樣式,但是我搜索的時候,大部分都是寫的一些小程式自定義的tabBar的樣式,而當時我在網上有一個地方找到了這個模板,現在介紹給大家參考參考WXML程式碼:<import src="../../template/nav" /&g

定義導航如何增加右滑動返回的手勢

這幾天產品增加了個新需求,要求增加滑動返回的手勢。安卓上有返回按鈕,但是iOS上沒有返回按鈕,增加一個返回的手勢可以較大的提高使用者體驗。iOS7剛出來的時候系統增加了滑動返回手勢,感覺特別好,但是發現把導航欄隱藏,自定義的滑動返回手勢不好使。於是按照這個帖子(http:/

h5底部導航圖示切換

.footer_si{position: fixed;bottom: 0;width: 100%;height: 55px;background: #f5f5f5;overflow: hidden;} .footer_si_box{width: 33%;text-align:

再談小程序定義底部導航

hone const 版本 css custom 打開 單獨 自定義樣式 ram 小程序自定義tabBar再探索 前言 最近有很多微信開發者朋友在QQ上加我好友,忽然意識到大家對微信自定義底部導航欄需求還是挺大的,故而再次整理下底部導航欄組件開發思路。和之前的文章還是有些區

【Android定義控制元件】炫酷的底部導航

https://github.com/WakeHao/NavBar 基本使用 使用這個控制元件,只需要簡單的幾部 引入該控制元件到你的專案中 compile 'com.chen.wakehao.library:bottom-navigation-bar:1.0.0'

簡單的定義BottomBar-仿微信底部導航

今天寫一個簡單的自定義的BottomBar。 圖片文字都是比較隨意的,具體實現中自己可以修改。下面是實現圖: 首先我們現在佈局中把想要顯示的整個介面的基本佈局搭建成功。(其實主要在於設定你的Tab。 如果專案中用到Bootmbar的地方比較多 或者是你想複用性高一點的話