zoukankan      html  css  js  c++  java
  • Android 实现一个自定义电池框View

    2019-11-28

    关键字:自定义View、Android电池框、Android电量框


    效果图如下:

         

    小尺寸效果图如下:

    完整源码在文末。

    下面记述一下该View的实现思想与过程。

    首先我们来剖析一下这个电池View,它有一个圆角矩形的外边框。然后外边框的右侧有一个电池盖子。最后就是代表电量的灰色圆角矩形体了。

    仅需要三支画笔就能实现这个电池电量框View。唯一的难点就是计算这三个形状之间的距离了。

    在View初始化的时候我们先来创建这三支画笔,对它们的形状、颜色、粗细做个定义:

    private Paint batteryBodyPainter;
    private Paint batteryHeadPainter;
    private Paint mPowerPaint;//电量画笔
    
    batteryBodyPainter = new Paint();
    batteryBodyPainter.setColor(ResourcesManager.getColor(R.color.view_battery_shape));
    batteryBodyPainter.setAntiAlias(true);
    batteryBodyPainter.setStyle(Paint.Style.STROKE);
    batteryBodyPainter.setStrokeWidth(OUTLINE_THICKNESS);
    
    batteryHeadPainter
    = new Paint(); batteryHeadPainter.setColor(ResourcesManager.getColor(R.color.view_battery_shape)); batteryHeadPainter.setAntiAlias(true); batteryHeadPainter.setStyle(Paint.Style.FILL);
    mPowerPaint
    = new Paint(); mPowerPaint.setAntiAlias(true); mPowerPaint.setColor(ResourcesManager.getColor(R.color.view_battery_shape)); mPowerPaint.setStyle(Paint.Style.FILL);

    经过分析我们不难发现,构成电池View的三个要素中都是“矩形体”。因此我们在绘制View的时候就一定是用 drawRoundRect 方法来绘制的。因此我们还得定义分别代表这三个组成要素的矩形体,为了优化View性能,我们不能在 onDraw() 定义,而应该在View初始化时定义,仅在 onDraw 中修改展示尺寸以得到不同的视觉效果。

    private RectF outlineRect;//电池矩形
    private RectF mCapRect;//电池盖矩形
    private RectF batteryRect;//电量矩形
    
    outlineRect = new RectF();
    outlineRect.left = OUTLINE_THICKNESS;
    outlineRect.top = OUTLINE_THICKNESS;
    
    mCapRect = new RectF();
    batteryRect = new RectF();

    View初始化时要做的事情就这么多。

    接下来是计算尺寸了。这个操作必须放到 onMeasure() 中做,或者说至少要到 onMeasure() 方法执行过后才能去做。

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int specWidthSize = MeasureSpec.getSize(widthMeasureSpec);//
        int specHeightSize = MeasureSpec.getSize(heightMeasureSpec);////设置电池外框
        outlineRect.right = specWidthSize - OUTLINE_THICKNESS - CAP_WIDTH;
        outlineRect.bottom = specHeightSize - OUTLINE_THICKNESS;
    
        //设置电池盖矩形
        mCapRect.left = outlineRect.right;
        mCapRect.top = (float)specHeightSize / 2 - CAP_HEIGHT / 2;
        mCapRect.right = specWidthSize;
        mCapRect.bottom = (float)specHeightSize / 2 + CAP_HEIGHT / 2;
    
        //设置电池体
        batteryRect.left = outlineRect.left + GAP_OF_SHAPE_BODY;
        batteryRect.top = outlineRect.top + GAP_OF_SHAPE_BODY;
        batteryRect.bottom = outlineRect.bottom - GAP_OF_SHAPE_BODY;
    
        fullPowerWidth = outlineRect.right - GAP_OF_SHAPE_BODY - batteryRect.left;
    
        setMeasuredDimension(specWidthSize, specHeightSize);
    }

    这部分的目标就是根据View自身的尺寸来确定电池框、电池盖以及电池体的相对位置。而关于处理三者之间间距的问题,基本只能靠微调尝试来完成了。这个工作倒也不难,笔者这里已经调好有相关参数的了。

    接下来就是View的绘制,即 onDraw() 咯。这部分的工作就更简单了,用前面定义的三支画笔以及三个矩形属性在画布上绘制圆角矩形。顺便再根据电量值来计算一下电池体的宽度。仅此而已。

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //根据电量值计算电池体的宽度
        batteryRect.right = (float)battery / 100 * fullPowerWidth + batteryRect.left;
    
        canvas.drawRoundRect(outlineRect, ROUND_CORNER_RADIUS, ROUND_CORNER_RADIUS, batteryBodyPainter);
        canvas.drawRoundRect(mCapRect, 1, 1, batteryHeadPainter);
        canvas.drawRoundRect(batteryRect,ROUND_CORNER_RADIUS,ROUND_CORNER_RADIUS, mPowerPaint);
    }

    最后,由于我们这个View是用来展示电池电量的,最基本的查询、设置电量值的接口也是不能少的。

    public void setBattery(int battery){
        this.battery = battery > 100 ? 100 : battery < 1 ? 1 : battery;
        Logger.d(TAG, "setting battery:" + battery + ",applied battery:" + this.battery);
    
        invalidate();
    }
    
    public int getBattery(){
        return battery;
    }

    以上就是一个自定义View实现的电池框View的基本过程了。

    package com.demo.views;
    
    import android.content.Context;
    import android.graphics.Canvas;
    import android.graphics.Paint;
    import android.graphics.RectF;
    import android.util.AttributeSet;
    import android.view.View;
    
    import com.demo.R;
    import com.demo.utils.Logger;
    import com.demo.utils.ResourcesManager;
    
    
    public class BatteryView extends View {
    
        private static final String TAG = "BatteryView";
    
        private static final float OUTLINE_THICKNESS = 2.0f;//电池框厚度
        private static final float CAP_WIDTH = 2.0f;//电池盖宽度
        private static final float CAP_HEIGHT = 8.0f;//电池盖高度
        private static final float GAP_OF_SHAPE_BODY = 3.0f;//电池体与外框之间的间隙
        private static final float ROUND_CORNER_RADIUS = 3;
    
        private float fullPowerWidth; //满电量时电池体的宽度。
    
        private int battery = 1;
    
        private Paint batteryBodyPainter;
        private Paint batteryHeadPainter;
        private Paint mPowerPaint;//电量画笔
    
        private RectF outlineRect;//电池矩形
        private RectF mCapRect;//电池盖矩形
        private RectF batteryRect;//电量矩形
    
        public BatteryView(Context context) {
            this(context, null);
        }
    
        public BatteryView(Context context, AttributeSet attrs) {
            super(context, attrs);
    
            batteryBodyPainter = new Paint();
            batteryBodyPainter.setColor(ResourcesManager.getColor(R.color.view_battery_shape));
            batteryBodyPainter.setAntiAlias(true);
            batteryBodyPainter.setStyle(Paint.Style.STROKE);
            batteryBodyPainter.setStrokeWidth(OUTLINE_THICKNESS);
    
            batteryHeadPainter = new Paint();
            batteryHeadPainter.setColor(ResourcesManager.getColor(R.color.view_battery_shape));
            batteryHeadPainter.setAntiAlias(true);
            batteryHeadPainter.setStyle(Paint.Style.FILL);
    
            mPowerPaint = new Paint();
            mPowerPaint.setAntiAlias(true);
            mPowerPaint.setColor(ResourcesManager.getColor(R.color.view_battery_shape));
            mPowerPaint.setStyle(Paint.Style.FILL);
    
            outlineRect = new RectF();
            outlineRect.left = OUTLINE_THICKNESS;
            outlineRect.top = OUTLINE_THICKNESS;
    
            mCapRect = new RectF();
            batteryRect = new RectF();
        }
    
        public void setBattery(int battery){
            this.battery = battery > 100 ? 100 : battery < 1 ? 1 : battery;
            Logger.d(TAG, "setting battery:" + battery + ",applied battery:" + this.battery);
    
            invalidate();
        }
    
        public int getBattery(){
            return battery;
        }
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    
            int specWidthSize = MeasureSpec.getSize(widthMeasureSpec);//
            int specHeightSize = MeasureSpec.getSize(heightMeasureSpec);////设置电池外框
            outlineRect.right = specWidthSize - OUTLINE_THICKNESS - CAP_WIDTH;
            outlineRect.bottom = specHeightSize - OUTLINE_THICKNESS;
    
            //设置电池盖矩形
            mCapRect.left = outlineRect.right;
            mCapRect.top = (float)specHeightSize / 2 - CAP_HEIGHT / 2;
            mCapRect.right = specWidthSize;
            mCapRect.bottom = (float)specHeightSize / 2 + CAP_HEIGHT / 2;
    
            //设置电池体
            batteryRect.left = outlineRect.left + GAP_OF_SHAPE_BODY;
            batteryRect.top = outlineRect.top + GAP_OF_SHAPE_BODY;
            batteryRect.bottom = outlineRect.bottom - GAP_OF_SHAPE_BODY;
    
            fullPowerWidth = outlineRect.right - GAP_OF_SHAPE_BODY - batteryRect.left;
    
            setMeasuredDimension(specWidthSize, specHeightSize);
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            //设置电量矩形
            batteryRect.right = (float)battery / 100 * fullPowerWidth + batteryRect.left;
    
            canvas.drawRoundRect(outlineRect, ROUND_CORNER_RADIUS, ROUND_CORNER_RADIUS, batteryBodyPainter);
            canvas.drawRoundRect(mCapRect, 1, 1, batteryHeadPainter);
            canvas.drawRoundRect(batteryRect,ROUND_CORNER_RADIUS,ROUND_CORNER_RADIUS, mPowerPaint);
        }
    
    }
    自定义电池框View完整源码

  • 相关阅读:
    iap 详细
    血的教训,下次开工程 一点要写好判断空字符串方法
    iOS中的ScrollView
    自定义弹框加载方式
    CAGradientLayer简介(处理视图渐变色)
    iOS 制作view渐变的效果CAGradientLayer
    将vs2012的项目转化成VS2010
    关于Excel导入的HDR=YES; IMEX=1详解
    C#读取Excel表中的数据时,为何有些行的字段内容读取不到
    OLEDB读取EXCEL表格时,某些字段为空,怎么办?
  • 原文地址:https://www.cnblogs.com/chorm590/p/11288742.html
Copyright © 2011-2022 走看看