自定義角標

 

 

在res/values下新建attrs.xml文件

 

<declare-styleable name="BitmapSubscriptView">
    <attr name="subscript_bitmap" format="reference"/>

    <attr name="subscript_orientation">
        <enum name="top_right" value="0"/>
        <enum name="bottom_right" value="1"/>
        <enum name="bottom_center" value="2"/>
        <enum name="bottom_left" value="3"/>
        <enum name="top_left" value="4"/>
        <enum name="top_center" value="5"/>
    </attr>
    <attr name="subscript_radius" format="dimension"/>
    <attr name="subscript_color" format="color|reference"/>
    <attr name="angular_offset_x" format="dimension"/>
    <attr name="angular_offset_y" format="dimension"/>

    <attr name="subscript_text" format="integer"/>
    <attr name="subscript_text_color" format="color|reference"/>
</declare-styleable>

創建自定義View

public class BitmapSubscriptView extends View {

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

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

    public BitmapSubscriptView(Context context,  AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.BitmapSubscriptView);
        init(typedArray);
    }
}

初始化

    public static final  int TOP_RIGHT = 0;
    public static final  int BOTTOM_RIGHT = 1;
    public static final  int BOTTOM_CENTER = 2;
    public static final  int BOTTOM_LEFT = 3;
    public static final  int TOP_LEFT = 4;
    public static final  int TOP_CENTER = 5;

    /**
     * 默認類型
     */
    @IntDef({TOP_RIGHT, BOTTOM_RIGHT, BOTTOM_CENTER, BOTTOM_LEFT, TOP_LEFT,TOP_CENTER})
    @Retention(RetentionPolicy.SOURCE)
    private  @interface SubscriptOrientation {
    }    

    //文字畫筆
    private TextPaint textPaint;

    /**
     * 獲取文字畫筆
     */
    public Paint getTextPaint(){
        return textPaint;
    }

    //文字顏色
    private int textColor = ContextCompat.getColor(getContext().getApplicationContext(), R.color.colorWhite);

    /**
     * 設置角標中文字的顏色
     * @param textColor 文字顏色
     */
    public void setTextColor(int textColor){
        this.textColor = textColor;
        textPaint.setColor(textColor);
        invalidate();
    }

    //文字
    private String subscriptText = "0";

    /**
     * 設置角標中的文字
     * @param subscriptText 角標數字
     */
    public void setSubscriptText(String subscriptText){
        this.subscriptText = subscriptText;
        invalidate();
    }

    //角標畫筆
    private Paint subscriptPaint;

    /**
     * 獲取角標畫筆
     */
    public Paint getSubscriptPaint(){
        return subscriptPaint;
    }

    //角標顏色
    private int subscriptColor = ContextCompat.getColor(getContext().getApplicationContext(), R.color.colorAccent);

    /**
     * 設置角標填充顏色
     * @param subscriptColor 角標顏色
     */
    public void setSubscriptColor(int subscriptColor){
        this.subscriptColor = subscriptColor;
        subscriptPaint.setColor(subscriptColor);
        invalidate();
    }

    //角標半徑
    private float subscriptRadius ;

    /**
     * 設置角標半徑
     * @param subscriptRadius 半徑
     */
    public void setSubscriptRadius(float subscriptRadius){
        if (blankBitmap != null){
            blankBitmap = null;
        }
        this.subscriptRadius = subscriptRadius;
        invalidate();
    }

    //角標X軸偏移量
    private float angularOffsetX = 0 ;

    /**
     * 設置角標X軸偏移量
     * @param angularOffsetX 正數:向右;負數:向左
     */
    public void setAngularOffsetX(float angularOffsetX){
        this.angularOffsetX = angularOffsetX;
        invalidate();
    }

    //角標Y軸偏移量
    private float angularOffsetY = 0 ;

    /**
     * 設置角標Y軸偏移量
     * @param angularOffsetY 正數:向下;負數:向上
     */
    public void setAngularOffsetY(float angularOffsetY){
        this.angularOffsetY = angularOffsetY;
        invalidate();
    }

    //角標位置
    private int subscriptOrientation;

    /**
     * 設置角標位置
     * @param subscriptOrientation 右上,右下,中下,左下,左上,左中
     */
    public void setSubscriptOrientation(@SubscriptOrientation int subscriptOrientation){
        this.subscriptOrientation = subscriptOrientation;
        invalidate();
    }

    //空白位圖
    private Bitmap blankBitmap;

    //位圖
    private Bitmap bitmap;

    /**
     * 設置位圖
     * @param id id
     * @param isRGB 是否使用RGB_565壓縮圖片
     */
    public void setBitmap(@DrawableRes int id,boolean isRGB){
        if (blankBitmap != null){
            blankBitmap = null;
        }
        bitmap = getBitmapResources(getResources(), id, isRGB);
        invalidate();
    }

    /**
     * 設置位圖
     * @param bitmap bitmap
     */
    public void setBitmap(Bitmap bitmap) {
        if (blankBitmap != null){
            blankBitmap = null;
        }
        this.bitmap = bitmap;
        invalidate();
    }

    //屏幕寬高
    private int width;
    private int height;

    private void init(TypedArray typedArray) {
        subscriptOrientation = typedArray.getInt(R.styleable.BitmapSubscriptView_subscript_orientation,0);
        angularOffsetX = typedArray.getDimension(R.styleable.BitmapSubscriptView_angular_offset_x,angularOffsetX);
        angularOffsetY = typedArray.getDimension(R.styleable.BitmapSubscriptView_angular_offset_y,angularOffsetY);
        subscriptRadius = typedArray.getDimension(R.styleable.BitmapSubscriptView_subscript_radius,0);
        subscriptColor = typedArray.getColor(R.styleable.BitmapSubscriptView_subscript_color,subscriptColor);
        subscriptText = typedArray.getString(R.styleable.BitmapSubscriptView_subscript_text);
        textColor = typedArray.getColor(R.styleable.BitmapSubscriptView_subscript_text_color,textColor);
        int id = typedArray.getResourceId(R.styleable.BitmapSubscriptView_subscript_bitmap,R.drawable.ic_launcher);
        bitmap = getBitmapResources(getResources(),id,false);

        typedArray.recycle();

        if (subscriptText == null){
            subscriptText = "0";
        }

        subscriptPaint = new Paint();
        subscriptPaint.setColor(subscriptColor);
        subscriptPaint.setStyle(Paint.Style.FILL);
        subscriptPaint.setAntiAlias(true);

        textPaint = new TextPaint();
        textPaint.setColor(textColor);
        textPaint.setTextAlign(Paint.Align.CENTER);
        textPaint.setAntiAlias(true);

        screenWidth();
    }

    /**
     * 讀取資源文件夾下圖片
     *
     * @param res   getResources
     * @param id    文件id
     * @param isRGB 是否使用RGB_565壓縮圖片
     * @return bitmap
     */
    public Bitmap getBitmapResources(Resources res, int id, boolean isRGB) {
        TypedValue value = new TypedValue();
        InputStream is = res.openRawResource(id, value);
        if (isRGB) {
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inPreferredConfig = Bitmap.Config.RGB_565;
            return BitmapFactory.decodeStream(new BufferedInputStream(is), null, options);
        }
        return BitmapFactory.decodeStream(new BufferedInputStream(is));
    }

    /**
     * 獲取屏幕寬高
     */
    private void screenWidth() {
        WindowManager wm = (WindowManager) getContext().getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
        if (wm != null) {
            Display display = wm.getDefaultDisplay();
            Point size = new Point();
            display.getSize(size);
            width = size.x;
            height = size.y;
        }
    }

繪製

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

        //最短邊距
        int length = Math.min(getWidth(),getHeight());
        //如果沒有設置角標半徑,或者角標直徑大於等於最短邊距,那麼subscriptRadius = 最短邊距的6分之1
        if (subscriptRadius == 0){
            subscriptRadius = length/6f;
        }else if (2*subscriptRadius >= length){
            subscriptRadius = length/6f;
        }

        if (blankBitmap == null){
            //新圖繪製區域高寬
            float width = getWidth() - 2*subscriptRadius;
            float height = getHeight() - 2*subscriptRadius;
            //縮放比例
            float scale = Math.min(width/bitmap.getWidth(),height/bitmap.getHeight());
            //新圖大小
            int a = (int) (bitmap.getWidth()*scale);
            int b = (int) (bitmap.getHeight()*scale);
            //創建空白位圖
            blankBitmap = Bitmap.createBitmap(a, b,Bitmap.Config.ARGB_8888);
            Canvas blankCanvas = new Canvas(blankBitmap);
            //將傳入的圖片繪製到空白位圖上
            Matrix matrix = new Matrix();
            matrix.setScale(scale,scale);
            blankCanvas.drawBitmap(bitmap, matrix,subscriptPaint);
        }

        // 新圖X座標 =(控件寬 - 新圖寬)/ 2
        float x = (getWidth() - blankBitmap.getWidth())/2f;
        float y = (getHeight() - blankBitmap.getHeight())/2f;
        //繪製新圖
        canvas.drawBitmap(blankBitmap,x,y,subscriptPaint);

        // 角標X座標 = (控件寬 + 新圖寬)/2
        float subscriptX;
        float subscriptY;
        switch (subscriptOrientation){
            case BOTTOM_RIGHT:
                subscriptX = (getWidth() + blankBitmap.getWidth())/2f + angularOffsetX;
                subscriptY = (getHeight() + blankBitmap.getHeight())/2f + angularOffsetY;
                break;
            case BOTTOM_CENTER:
                subscriptX = getWidth()/2f + angularOffsetX;
                subscriptY = (getHeight() + blankBitmap.getHeight())/2f + angularOffsetY;
                break;
            case BOTTOM_LEFT:
                subscriptX = (getWidth() - blankBitmap.getWidth())/2f + angularOffsetX;
                subscriptY = (getHeight() + blankBitmap.getHeight())/2f + angularOffsetY;
                break;
            case TOP_LEFT:
                subscriptX = (getWidth() - blankBitmap.getWidth())/2f + angularOffsetX;
                subscriptY = (getHeight() - blankBitmap.getHeight())/2f + angularOffsetY;
                break;
            case TOP_CENTER:
                subscriptX = getWidth()/2f + angularOffsetX;
                subscriptY = (getHeight() - blankBitmap.getHeight())/2f + angularOffsetY;
                break;
            default:
                subscriptX = (getWidth() + blankBitmap.getWidth())/2f + angularOffsetX;
                subscriptY = (getHeight() - blankBitmap.getHeight())/2f + angularOffsetY;
                break;
        }

        //繪製角標
        canvas.drawCircle(subscriptX ,  subscriptY , subscriptRadius ,subscriptPaint);

        textPaint.setTextSize(subscriptRadius/2);
        //繪製角標中的數字
        canvas.drawText(subscriptText,subscriptX, subscriptY - textPaint.ascent()/2f ,textPaint);
    }

測量

@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int measureWidth = MeasureSpec.getSize(widthMeasureSpec);
        int measureHeight = MeasureSpec.getSize(heightMeasureSpec);
        int measureWidthMode = MeasureSpec.getMode(widthMeasureSpec);
        int measureHeightMode = MeasureSpec.getMode(heightMeasureSpec);

        //限制控件大小不能大於屏幕寬高
        setMeasuredDimension((measureWidthMode == MeasureSpec.EXACTLY) ? Math.min(measureWidth, width) : Math.min(bitmap.getWidth(), width)
                , (measureHeightMode == MeasureSpec.EXACTLY) ? Math.min(measureHeight, height) : Math.min(bitmap.getHeight(), height));
    }

使用

//設置圖片
bitmapSubscriptView.setBitmap(R.drawable.test,false)
bitmapSubscriptView.setBitmap(bitmap)
//設置角標顏色和半徑
bitmapSubscriptView.setSubscriptColor(R.color.colorAccent)
bitmapSubscriptView.setSubscriptRadius(10f)
//設置角標方位和偏移量
bitmapSubscriptView.setSubscriptOrientation(BitmapSubscriptView.TOP_LEFT)
bitmapSubscriptView.setAngularOffsetX(100f)
bitmapSubscriptView.setAngularOffsetY(100f)
//設置角標文字和顏色
bitmapSubscriptView.setSubscriptText("1")
bitmapSubscriptView.setTextColor(R.color.colorWhite)
app:subscript_bitmap="@drawable/test"
app:subscript_radius="40dp"
app:subscript_orientation="bottom_right"
app:subscript_color="@color/colorAccent"
app:subscript_text="1"
app:subscript_text_color="@color/colorWhite"
app:angular_offset_x="-10dp"
app:angular_offset_y="10dp"

完整代碼

public class BitmapSubscriptView extends View {

    public static final  int TOP_RIGHT = 0;
    public static final  int BOTTOM_RIGHT = 1;
    public static final  int BOTTOM_CENTER = 2;
    public static final  int BOTTOM_LEFT = 3;
    public static final  int TOP_LEFT = 4;
    public static final  int TOP_CENTER = 5;

    /**
     * 默認類型
     */
    @IntDef({TOP_RIGHT, BOTTOM_RIGHT, BOTTOM_CENTER, BOTTOM_LEFT, TOP_LEFT,TOP_CENTER})
    @Retention(RetentionPolicy.SOURCE)
    private  @interface SubscriptOrientation {
    }

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

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

    public BitmapSubscriptView(Context context,  AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.BitmapSubscriptView);
        init(typedArray);
    }

    //文字畫筆
    private TextPaint textPaint;

    /**
     * 獲取文字畫筆
     */
    public Paint getTextPaint(){
        return textPaint;
    }

    //文字顏色
    private int textColor = ContextCompat.getColor(getContext().getApplicationContext(), R.color.colorWhite);

    /**
     * 設置角標中文字的顏色
     * @param textColor 文字顏色
     */
    public void setTextColor(int textColor){
        this.textColor = textColor;
        textPaint.setColor(textColor);
        invalidate();
    }

    //文字
    private String subscriptText = "0";

    /**
     * 設置角標中的文字
     * @param subscriptText 角標數字
     */
    public void setSubscriptText(String subscriptText){
        this.subscriptText = subscriptText;
        invalidate();
    }

    //角標畫筆
    private Paint subscriptPaint;

    /**
     * 獲取角標畫筆
     */
    public Paint getSubscriptPaint(){
        return subscriptPaint;
    }

    //角標顏色
    private int subscriptColor = ContextCompat.getColor(getContext().getApplicationContext(), R.color.colorAccent);

    /**
     * 設置角標填充顏色
     * @param subscriptColor 角標顏色
     */
    public void setSubscriptColor(int subscriptColor){
        this.subscriptColor = subscriptColor;
        subscriptPaint.setColor(subscriptColor);
        invalidate();
    }

    //角標半徑
    private float subscriptRadius ;

    /**
     * 設置角標半徑
     * @param subscriptRadius 半徑
     */
    public void setSubscriptRadius(float subscriptRadius){
        this.subscriptRadius = subscriptRadius;
        invalidate();
    }

    //角標X軸偏移量
    private float angularOffsetX = 0 ;

    /**
     * 設置角標X軸偏移量
     * @param angularOffsetX 正數:向右;負數:向左
     */
    public void setAngularOffsetX(float angularOffsetX){
        this.angularOffsetX = angularOffsetX;
        invalidate();
    }

    //角標Y軸偏移量
    private float angularOffsetY = 0 ;

    /**
     * 設置角標Y軸偏移量
     * @param angularOffsetY 正數:向下;負數:向上
     */
    public void setAngularOffsetY(float angularOffsetY){
        this.angularOffsetY = angularOffsetY;
        invalidate();
    }

    //角標位置
    private int subscriptOrientation;

    /**
     * 設置角標位置
     * @param subscriptOrientation 右上,右下,中下,左下,左上,左中
     */
    public void setSubscriptOrientation(@SubscriptOrientation int subscriptOrientation){
        this.subscriptOrientation = subscriptOrientation;
        invalidate();
    }

    //空白位圖
    private Bitmap blankBitmap;

    //位圖
    private Bitmap bitmap;

    /**
     * 設置位圖
     * @param id id
     * @param isRGB 是否使用RGB_565壓縮圖片
     */
    public void setBitmap(@DrawableRes int id,boolean isRGB){
        bitmap = getBitmapResources(getResources(), id, isRGB);
        invalidate();
    }

    /**
     * 設置位圖
     * @param bitmap bitmap
     */
    public void setBitmap(Bitmap bitmap) {
        this.bitmap = bitmap;
        invalidate();
    }

    //屏幕寬高
    private int width;
    private int height;

    private void init(TypedArray typedArray) {
        subscriptOrientation = typedArray.getInt(R.styleable.BitmapSubscriptView_subscript_orientation,0);
        angularOffsetX = typedArray.getDimension(R.styleable.BitmapSubscriptView_angular_offset_x,angularOffsetX);
        angularOffsetY = typedArray.getDimension(R.styleable.BitmapSubscriptView_angular_offset_y,angularOffsetY);
        subscriptRadius = typedArray.getDimension(R.styleable.BitmapSubscriptView_subscript_radius,0);
        subscriptColor = typedArray.getColor(R.styleable.BitmapSubscriptView_subscript_color,subscriptColor);
        subscriptText = typedArray.getString(R.styleable.BitmapSubscriptView_subscript_text);
        textColor = typedArray.getColor(R.styleable.BitmapSubscriptView_subscript_text_color,textColor);
        int id = typedArray.getResourceId(R.styleable.BitmapSubscriptView_subscript_bitmap,R.drawable.ic_launcher);
        bitmap = getBitmapResources(getResources(),id,false);

        typedArray.recycle();

        if (subscriptText == null){
            subscriptText = "0";
        }

        subscriptPaint = new Paint();
        subscriptPaint.setColor(subscriptColor);
        subscriptPaint.setStyle(Paint.Style.FILL);
        subscriptPaint.setAntiAlias(true);

        textPaint = new TextPaint();
        textPaint.setColor(textColor);
        textPaint.setTextAlign(Paint.Align.CENTER);
        textPaint.setAntiAlias(true);

        screenWidth();
    }

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

        //最短邊距
        int length = Math.min(getWidth(),getHeight());
        //如果沒有設置角標半徑,或者角標直徑大於等於最短邊距,那麼subscriptRadius = 最短邊距的6分之1
        if (subscriptRadius == 0){
            subscriptRadius = length/6f;
        }else if (2*subscriptRadius >= length){
            subscriptRadius = length/6f;
        }

        if (blankBitmap == null){
            //新圖繪製區域高寬
            float width = getWidth() - 2*subscriptRadius;
            float height = getHeight() - 2*subscriptRadius;
            //縮放比例
            float scale = Math.min(width/bitmap.getWidth(),height/bitmap.getHeight());
            //新圖大小
            int a = (int) (bitmap.getWidth()*scale);
            int b = (int) (bitmap.getHeight()*scale);
            //創建空白位圖
            blankBitmap = Bitmap.createBitmap(a, b,Bitmap.Config.ARGB_8888);
            Canvas blankCanvas = new Canvas(blankBitmap);
            //將傳入的圖片繪製到空白位圖上
            Matrix matrix = new Matrix();
            matrix.setScale(scale,scale);
            blankCanvas.drawBitmap(bitmap, matrix,subscriptPaint);
        }

        // 新圖X座標 =(控件寬 - 新圖寬)/ 2
        float x = (getWidth() - blankBitmap.getWidth())/2f;
        float y = (getHeight() - blankBitmap.getHeight())/2f;
        //繪製新圖
        canvas.drawBitmap(blankBitmap,x,y,subscriptPaint);

        // 角標X座標 = (控件寬 + 新圖寬)/2
        float subscriptX;
        float subscriptY;
        switch (subscriptOrientation){
            case BOTTOM_RIGHT:
                subscriptX = (getWidth() + blankBitmap.getWidth())/2f + angularOffsetX;
                subscriptY = (getHeight() + blankBitmap.getHeight())/2f + angularOffsetY;
                break;
            case BOTTOM_CENTER:
                subscriptX = getWidth()/2f + angularOffsetX;
                subscriptY = (getHeight() + blankBitmap.getHeight())/2f + angularOffsetY;
                break;
            case BOTTOM_LEFT:
                subscriptX = (getWidth() - blankBitmap.getWidth())/2f + angularOffsetX;
                subscriptY = (getHeight() + blankBitmap.getHeight())/2f + angularOffsetY;
                break;
            case TOP_LEFT:
                subscriptX = (getWidth() - blankBitmap.getWidth())/2f + angularOffsetX;
                subscriptY = (getHeight() - blankBitmap.getHeight())/2f + angularOffsetY;
                break;
            case TOP_CENTER:
                subscriptX = getWidth()/2f + angularOffsetX;
                subscriptY = (getHeight() - blankBitmap.getHeight())/2f + angularOffsetY;
                break;
            default:
                subscriptX = (getWidth() + blankBitmap.getWidth())/2f + angularOffsetX;
                subscriptY = (getHeight() - blankBitmap.getHeight())/2f + angularOffsetY;
                break;
        }

        //繪製角標
        canvas.drawCircle(subscriptX ,  subscriptY , subscriptRadius ,subscriptPaint);

        textPaint.setTextSize(subscriptRadius/2);
        //繪製角標中的數字
        canvas.drawText(subscriptText,subscriptX, subscriptY - textPaint.ascent()/2f ,textPaint);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int measureWidth = MeasureSpec.getSize(widthMeasureSpec);
        int measureHeight = MeasureSpec.getSize(heightMeasureSpec);
        int measureWidthMode = MeasureSpec.getMode(widthMeasureSpec);
        int measureHeightMode = MeasureSpec.getMode(heightMeasureSpec);

        //限制控件大小不能大於屏幕寬高
        setMeasuredDimension((measureWidthMode == MeasureSpec.EXACTLY) ? Math.min(measureWidth, width) : Math.min(bitmap.getWidth(), width)
                , (measureHeightMode == MeasureSpec.EXACTLY) ? Math.min(measureHeight, height) : Math.min(bitmap.getHeight(), height));
    }

    /**
     * 讀取資源文件夾下圖片
     *
     * @param res   getResources
     * @param id    文件id
     * @param isRGB 是否使用RGB_565壓縮圖片
     * @return bitmap
     */
    public Bitmap getBitmapResources(Resources res, int id, boolean isRGB) {
        TypedValue value = new TypedValue();
        InputStream is = res.openRawResource(id, value);
        if (isRGB) {
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inPreferredConfig = Bitmap.Config.RGB_565;
            return BitmapFactory.decodeStream(new BufferedInputStream(is), null, options);
        }
        return BitmapFactory.decodeStream(new BufferedInputStream(is));
    }

    /**
     * 獲取屏幕寬高
     */
    private void screenWidth() {
        WindowManager wm = (WindowManager) getContext().getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
        if (wm != null) {
            Display display = wm.getDefaultDisplay();
            Point size = new Point();
            display.getSize(size);
            width = size.x;
            height = size.y;
        }
    }
}

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章