自定义万能的progressView

原创 2015年12月18日 17:59:21

效果预览

这里写图片描述

控件由来

这两天有个哥们给我商量他们公司语音播放进度条的做法。如图这里写图片描述
看到这个图片我首先想到的是自定义view,怎么自定义view呢?

第一个想法

数一下一共有多少根竖条,然后找到每一根竖条直接高度的比例,通过自定义view宽高的比例算数每个竖条和中间横条的位置。这个办法肯定是可以的,但是感觉有点麻烦而且不通用,万一哪天设计的妹子把这个进度图换了我还得重新找规律重新通过复杂的计算来做。

第二种想法

其实这种进度的显示就是两个图层。第一个图层显示灰色全部画下来,第二个要根据进度画出不发蓝色图层就可以了。而且这种方法放之四海都可以用(只要让设计MM给你切两个大小一致颜色不同的图片就ok了)


编码

通过上边的比较我们决定用第二种方法来实现

我们先来分析下我们需要哪些属性:

  • 我们要两个大小相等颜色不同的图片
  • 当前进度和总进度

分析了下好像就学这四个属性就够了于是我们先定attr

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="MyProgress">
        <attr name="bg_drawable" format="reference"></attr>
        <attr name="progress_drawable" format="reference"></attr>
        <attr name="progress" format="integer"></attr>
        <attr name="max_progress" format="integer"></attr>
        <attr name="orientation" format="enum">
            <enum name="left" value="0"></enum>
            <enum name="top" value="1"></enum>
            <enum name="right" value="2"></enum>
            <enum name="bottom" value="3"></enum>
        </attr>
    </declare-styleable>
</resources>

好像多了一个属性orientation,既然是是自定义要放之四海皆准我们就要考虑到他进度方向有可能是从左向右,有可能是从下往上,所以这里我定义了4个方向

再看看我的自定义view的java代码

  • 定义上边需要的5个属性变量并在构造函数里获取到赋值
public MyProgress(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray typedArray=context.obtainStyledAttributes(attrs,R.styleable.MyProgress,defStyleAttr,0);
        //背景图片
        res_bg= typedArray.getResourceId(R.styleable.MyProgress_bg_drawable,0);
        //进度图片
        res_progress=typedArray.getResourceId(R.styleable.MyProgress_progress_drawable,0);
        /方向
        orientation=typedArray.getInteger(R.styleable.MyProgress_orientation, 0);
        //最大进度
        max=typedArray.getInteger(R.styleable.MyProgress_max_progress,100);
        //进度值并转化为百分比
        progressP=typedArray.getInteger(R.styleable.MyProgress_progress,100)*1.0f/max;
        typedArray.recycle();
        init();
    }
  • 既然自定义view就要重写onMeasure确定它的宽高,这个宽高我们自然是用图片自己打宽高了,所以我们在init()里获取图片的bitmap和宽高,再onMeasure里设置成图片的宽高
private void init(){
        //进度图的bitmap
        if(res_progress!=0){
            mBlueBitmap= BitmapFactory.decodeResource(getResources(),res_progress);
        }else{
            mBlueBitmap= BitmapFactory.decodeResource(getResources(),R.mipmap.blue);
        }
        //背景图的bitmap
        if(res_bg!=0){
            mWhiteBitmap= BitmapFactory.decodeResource(getResources(),res_bg);
        }else {
            mWhiteBitmap= BitmapFactory.decodeResource(getResources(),R.mipmap.white);
        }
        //图片宽
        width=mBlueBitmap.getWidth();
        //图片高
        height=mBlueBitmap.getHeight();
    }
@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        setMeasuredDimension(width, height);
    }
  • 接下下来就是在onDraw()里画图了。其实就两步:1、画背景图 2、按进度比例截取进度图的部分图像,并画在画不上
@Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawBitmap(mWhiteBitmap, 0, 0, null);
         ImageCrop(canvas, mBlueBitmap, progressP);
    }
  • 那我们重点来看看这个截取图片的代码ImageCrop(),代码也很简单就是通过progress的进度值再结合定义的方向算出来对应的x,y坐标和对应截取图片的大小区域
 public  void ImageCrop(Canvas canvas,Bitmap bitmap,float progress) {
        int w = bitmap.getWidth(); // 得到图片的宽,高
        int h = bitmap.getHeight();
        int x=0;
        int y=0;
        if(orientation==0){
            w=(int) (w*progress);
        }
        if(orientation==1){
            h=(int)(h*progress);
        }
        if(orientation==2){
            x=w-(int)(w*progress);
            w=(int)(w*progress);
        }
        if(orientation==3){
            y=h-(int)(h*progress);
            h=(int)(h*progress);
        }
        //下面这句是关键
        Bitmap tempBitmap=Bitmap.createBitmap(bitmap, x, y, w, h, null, false);
        canvas.drawBitmap(tempBitmap,x,y,null);
    }
  • 到这里这个自定义view已经可以用了,但是我们通常的进度是通过代码控制的 所以我们加个方法来控制进度值progress
public void setProgress(int progress){
        this.progressP=progress*1.0f/max;
        invalidate();
    }
  • 接下来就是使用了,在xml里定义我们的view,在activity里new个线程调用调用setProgress
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:orientation="vertical"
    tools:context=".MainActivity"
    android:background="#000000">

    <com.leisure.progressview.MyProgress
        android:layout_margin="10dp"
        android:id="@+id/left_progress"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        app:orientation="left"
        app:bg_drawable="@mipmap/btn_photo_select_normal"
        app:progress_drawable="@mipmap/btn_photo_select_push"
        app:progress="50"
        app:max_progress="100"/>
    <com.leisure.progressview.MyProgress
        android:layout_margin="10dp"
        android:id="@+id/top_progress"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        app:orientation="top"
        app:bg_drawable="@mipmap/btn_file_browser_up_level_normal"
        app:progress_drawable="@mipmap/btn_file_browser_up_level_pressed"
        app:progress="50"
        app:max_progress="100"/>
    <com.leisure.progressview.MyProgress
        android:layout_margin="10dp"
        android:id="@+id/right_progress"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        app:orientation="right"
        app:bg_drawable="@mipmap/enterprise_normal"
        app:progress_drawable="@mipmap/enterprise_press"
        app:progress="50"
        app:max_progress="100"/>
    <com.leisure.progressview.MyProgress
        android:layout_margin="10dp"
        android:id="@+id/bottom_progress"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        app:orientation="bottom"
        app:progress="50"
        app:max_progress="100"/>

</LinearLayout>
package com.leisure.progressview;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {
    MyProgress mProgressLeft,mProgressTop,mProgressRight,mProgressBottom;
    Handler mHandler=new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            mProgressLeft.setProgress(msg.what);
            mProgressTop.setProgress(msg.what);
            mProgressRight.setProgress(msg.what);
            mProgressBottom.setProgress(msg.what);
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mProgressLeft= (MyProgress) findViewById(R.id.left_progress);
        mProgressTop= (MyProgress) findViewById(R.id.top_progress);
        mProgressRight= (MyProgress) findViewById(R.id.right_progress);
        mProgressBottom= (MyProgress) findViewById(R.id.bottom_progress);
        new Thread(){
            @Override
            public void run() {
                super.run();
                for(int i=1;i<=100;i++){
                    mHandler.sendEmptyMessage(i);
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();

    }
}

总结

自己总是特别懒,不愿意多动脑,但是比较乐于助人,如果是自己的事可能就不会写这个控件了,但是朋友给机会讨论 我就写个试试吧 感谢这个朋友给的机会 就刚学android的时候写过博客 ,好久没有写了希望有人能看懂

github地址:https://github.com/leisurelife/ProgressView

自定义个UIProgressView(可自己设置高度)

由于项目需求中的加载进度条的高度比系统原生的高度要小一些,于是乎就继承UIView自己写了个UIProgressView...
  • dengmeiyu
  • dengmeiyu
  • 2014年03月26日 15:26
  • 2183

iOS自定义progressView的实现

最近越来越多的iOS APP 中使用到了进度条这一控件,虽然苹果的UIKIT框架给我们提供了UIProgressView这一控件,但是提供的相应的API内容不是很丰富,开发中只能实现一些简单的效果,但...
  • qq_30286135
  • qq_30286135
  • 2016年05月01日 16:19
  • 4099

自定义一个进度条为圆角的progressbar

请看源码,注释神马的都很清楚 1、java代码 package com.xctz.niceman.customcanvas; import android.content.Context; imp...
  • luanxuye
  • luanxuye
  • 2016年11月04日 11:42
  • 820

自定义View之渐变色圆形进度条

先展示下效果图,然后按照自定义view的步骤来实现。 目标是渐变色圆形进度条,那么,使用canvas画弧形是基础了,另外是渐变色的效果,这里使用LinearGradient来实现。 既然是提供一个进...
  • lintax
  • lintax
  • 2016年09月06日 22:01
  • 2695

Android自定义View——自定义ViewPager

手把手教你制作自定义ViewPager 事先说明: 本篇文章会介绍:自定义ViewPager的创建,处理滑动监听,处理滑动冲突,增加ViewPager的指示器等 文章也会涉及到手势识别器和Scro...
  • qq_30379689
  • qq_30379689
  • 2016年08月26日 23:03
  • 4097

[Android开发] 自定义View之消息数量提示View-TipView

自定义View之消息数量提示View-TipView一、功能 效果图 一个View就像实现,支持设置 背景色、数量文字、文字颜色、文字大小、最大文字、只显示圆点,自动适配文字大小,不会超出圆圈的范...
  • niubitianping
  • niubitianping
  • 2016年09月09日 20:11
  • 1271

iOS进度条 自定义圆角 UIProgressView

进度条总结,自定义圆角大小,多种方法定义圆角大小 //实例化一个进度条,有两种样式,一种是UIProgressViewStyleBar一种是UIProgressViewS...
  • YCM1101743158
  • YCM1101743158
  • 2016年10月18日 15:37
  • 2720

[Android]自定义万能Dialog

在我们开发Android项目的时候,难免需要制作各式各样的Dialog,例如:
  • u011596810
  • u011596810
  • 2016年05月25日 21:36
  • 2334

Android 自定义view完全解析--带你通透了解自定义view

参考转自郭霖博客带你一步步深入了解View系列 Android LayoutInflater原理分析 相信接触Android久一点的朋友对于LayoutInflater...
  • u011200604
  • u011200604
  • 2017年02月22日 15:26
  • 7296

Android从零开搞系列:自定义View(5)基本的自定义ViewPager指示器+开源项目分析(下)

开源ViewPager指示器MagicIndicator的思路分析+源码分析
  • wjzj000
  • wjzj000
  • 2016年12月15日 08:52
  • 1196
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:自定义万能的progressView
举报原因:
原因补充:

(最多只允许输入30个字)