自定义角标

it2022-05-05  134

 

 

在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; } } }

 

 

 

 

 

 

 


最新回复(0)