Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a battery level indicator in android?

enter image description here

I want to create a battery level indicator as in the image(which i circled). The green part should fill based on the available battery in the device.

Getting the battery percentage from the device like this

registerReceiver(mBatInfoReceiver, new IntentFilter(
            Intent.ACTION_BATTERY_CHANGED));

So in the layout i am able to display the battery percentage.

public class BatteryIndicatorActivity extends Activity {
        //Create Broadcast Receiver Object along with class definition
    private BroadcastReceiver mBatInfoReceiver = new BroadcastReceiver() {
        @Override
          //When Event is published, onReceive method is called
        public void onReceive(Context c, Intent i) {
              //Get Battery %
            int level = i.getIntExtra("level", 0);
            TextView tv = (TextView) findViewById(R.id.textfield);
              //Set TextView with text
            tv.setText("Battery Level: " + Integer.toString(level) + "%");
        }

    };

But how to create a UI for this type of battery indicator. Is their any api to achieve this?, If not how to create such type of UI.

Your help will be appreciated.

like image 771
Anuraj R Avatar asked Dec 09 '25 19:12

Anuraj R


2 Answers

Here is my CustomView for display battery level

class BatteryView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) :
    View(context, attrs, defStyleAttr) {
    private var radius: Float = 0f
    private var isCharging: Boolean = false

    // Top
    private var topPaint =
        PaintDrawable(Color.WHITE) // I only want to corner top-left and top-right so I use PaintDrawable instead of Paint
    private var topRect = Rect()
    private var topPaintWidthPercent = 50
    private var topPaintHeightPercent = 8

    // Border
    private var borderPaint = Paint().apply {
        color = Color.BLUE
        style = Paint.Style.STROKE
    }
    private var borderRect = RectF()
    private var borderStrokeWidthPercent = 8
    private var borderStroke: Float = 0f

    // Percent
    private var percentPaint = Paint()
    private var percentRect = RectF()
    private var percentRectTopMin = 0f
    private var percent: Int = 0

    // Charging
    private var chargingRect = RectF()
    private var chargingBitmap: Bitmap? = null

    init {
        init(attrs)
        chargingBitmap = getBitmap(R.drawable.ic_charging)
    }

    private fun init(attrs: AttributeSet?) {
        val ta = context.obtainStyledAttributes(attrs, R.styleable.BatteryView)
        try {
            percent = ta.getInt(R.styleable.BatteryView_bv_percent, 0)
            isCharging = ta.getBoolean(R.styleable.BatteryView_bv_charging, false)
        } finally {
            ta.recycle()
        }
    }

    @SuppressLint("DrawAllocation")
    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        val measureWidth = View.getDefaultSize(suggestedMinimumWidth, widthMeasureSpec)
        val measureHeight = (measureWidth * 1.8f).toInt()
        setMeasuredDimension(measureWidth, measureHeight)

        radius = borderStroke / 2
        borderStroke = (borderStrokeWidthPercent * measureWidth).toFloat() / 100

        // Top
        val topLeft = measureWidth * ((100 - topPaintWidthPercent) / 2) / 100
        val topRight = measureWidth - topLeft
        val topBottom = topPaintHeightPercent * measureHeight / 100
        topRect = Rect(topLeft, 0, topRight, topBottom)

        // Border
        val borderLeft = borderStroke / 2
        val borderTop = topBottom.toFloat() + borderStroke / 2
        val borderRight = measureWidth - borderStroke / 2
        val borderBottom = measureHeight - borderStroke / 2
        borderRect = RectF(borderLeft, borderTop, borderRight, borderBottom)

        // Progress
        val progressLeft = borderStroke
        percentRectTopMin = topBottom + borderStroke
        val progressRight = measureWidth - borderStroke
        val progressBottom = measureHeight - borderStroke
        percentRect = RectF(progressLeft, percentRectTopMin, progressRight, progressBottom)

        // Charging Image
        val chargingLeft = borderStroke
        var chargingTop = topBottom + borderStroke
        val chargingRight = measureWidth - borderStroke
        var chargingBottom = measureHeight - borderStroke
        val diff = ((chargingBottom - chargingTop) - (chargingRight - chargingLeft))
        chargingTop += diff / 2
        chargingBottom -= diff / 2
        chargingRect = RectF(chargingLeft, chargingTop, chargingRight, chargingBottom)
    }

    override fun onDraw(canvas: Canvas) {
        drawTop(canvas)
        drawBody(canvas)
        if (!isCharging) {
            drawProgress(canvas, percent)
        } else {
            drawCharging(canvas)
        }
    }

    private fun drawTop(canvas: Canvas) {
        topPaint.bounds = topRect
        topPaint.setCornerRadii(floatArrayOf(radius, radius, radius, radius, 0f, 0f, 0f, 0f))
        topPaint.draw(canvas)
    }

    private fun drawBody(canvas: Canvas) {
        borderPaint.strokeWidth = borderStroke
        canvas.drawRoundRect(borderRect, radius, radius, borderPaint)
    }

    private fun drawProgress(canvas: Canvas, percent: Int) {
        percentPaint.color = getPercentColor(percent)
        percentRect.top = percentRectTopMin + (percentRect.bottom - percentRectTopMin) * (100 - percent) / 100
        canvas.drawRect(percentRect, percentPaint)
    }

    // todo change color
    private fun getPercentColor(percent: Int): Int {
        if (percent > 50) {
            return Color.WHITE
        }
        if (percent > 30) {
            return Color.YELLOW
        }
        return Color.RED
    }

    private fun drawCharging(canvas: Canvas) {
        chargingBitmap?.let {
            canvas.drawBitmap(it, null, chargingRect, null)
        }
    }

    private fun getBitmap(drawableId: Int, desireWidth: Int? = null, desireHeight: Int? = null): Bitmap? {
        val drawable = AppCompatResources.getDrawable(context, drawableId) ?: return null
        val bitmap = Bitmap.createBitmap(
            desireWidth ?: drawable.intrinsicWidth,
            desireHeight ?: drawable.intrinsicHeight,
            Bitmap.Config.ARGB_8888
        )
        val canvas = Canvas(bitmap)
        drawable.setBounds(0, 0, canvas.width, canvas.height)
        drawable.draw(canvas)
        return bitmap
    }

    fun charge() {
        isCharging = true
        invalidate() // can improve by invalidate(Rect)
    }

    fun unCharge() {
        isCharging = false
        invalidate()
    }

    fun setPercent(percent: Int) {
        if (percent > 100 || percent < 0) {
            return
        }
        this.percent = percent
        invalidate()
    }

    fun getPercent(): Int {
        return percent
    }
}

style.xml

<declare-styleable name="BatteryView">
    <attr name="bv_charging" format="boolean" />
    <attr name="bv_percent" format="integer" />
</declare-styleable>

drawable/ic_charging.xml

<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="24dp"
    android:height="24dp"
    android:viewportWidth="368.492"
    android:viewportHeight="368.492">
    <path
        android:fillColor="#FFFFFF"
        android:pathData="M297.51,150.349c-1.411,-2.146 -3.987,-3.197 -6.497,-2.633l-73.288,16.498L240.039,7.012c0.39,-2.792 -1.159,-5.498 -3.766,-6.554c-2.611,-1.069 -5.62,-0.216 -7.283,2.054L71.166,217.723c-1.489,2.035 -1.588,4.773 -0.246,6.911c1.339,2.132 3.825,3.237 6.332,2.774l79.594,-14.813l-23.257,148.799c-0.436,2.798 1.096,5.536 3.714,6.629c0.769,0.312 1.562,0.469 2.357,0.469c1.918,0 3.78,-0.901 4.966,-2.517l152.692,-208.621C298.843,155.279 298.916,152.496 297.51,150.349z" />
</vector>

Using

<package.BatteryView
        android:id="@+id/battery_view"
        android:layout_width="150dp"
        android:layout_height="wrap_content"
        android:src="@drawable/ic_charging"
        app:bv_charging="false"
        app:bv_percent="20" />

Github project

Hope it help

like image 167
Linh Avatar answered Dec 12 '25 15:12

Linh


There are a lot of ways to do it. Here are few of them:

  1. Use a ProgressBar, make it vertical, make it be drawn in the battery shape
  2. Use a custom View, override onDraw() in it, and draw the battery shape on the canvas
  3. Use a white image with a transparent battery shape. Place it over a view, where you fill a background vertically, or change background view's height.
like image 37
Vladyslav Matviienko Avatar answered Dec 12 '25 15:12

Vladyslav Matviienko