Android自定义Progress控件的方法

发布时间 - 2026-01-11 02:16:24    点击率:

progress各种各样的都有,自定义大多数也是简单的,根据业务需求来自己定义,记录一下,先上效果图

本来想找个第三方改改就上的,不过自己的业务需求有点不搭,一下子没找到合适的,也没这么多时间去找了,想想还是自己写个吧,因为也简单。

主要就是需求就是椭圆进度,百分比跟随渐变背景,这样一想其实就是一个布局,然后控制里面的进度长度,或者移动,我这是控制长度,这样毕竟简单,而且扩展好,以后进度条有什么奇葩需求也好改。

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.support.annotation.AttrRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.TextView;

/**
 * Created by LiuZhen on 2017/7/8.
 */

public class UpdateProgressBar extends FrameLayout {

  private TextView tv_progress;
  private int width;
  private ViewGroup.LayoutParams params;
  /**
   * The progress text offset.
   */
  private int mOffset;
  /**
   * The progress text size.
   */
  private float mTextSize;
  /**
   * The progress text color.
   */
  private int mTextColor;
  private float default_text_size;
  /**
   * The progress area bar color.
   */
  private int mReachedBarColor;
  /**
   * The bar unreached area color.
   */
  private int mUnreachedBarColor;
  private final int default_reached_color = Color.rgb(66, 145, 241);
  private final int default_unreached_color = Color.rgb(204, 204, 204);
  private final int default_text_color = Color.rgb(66, 145, 241);

  public UpdateProgressBar(@NonNull Context context) {
    this(context,null);
  }

  public UpdateProgressBar(@NonNull Context context, @Nullable AttributeSet attrs) {
    this(context, attrs,0);
  }

  public UpdateProgressBar(@NonNull Context context, @Nullable AttributeSet attrs, @AttrRes int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    init(attrs, defStyleAttr);
  }

  @Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

    int desiredWidth = 100;
    int desiredHeight = 100;

    int widthMode = MeasureSpec.getMode(widthMeasureSpec);
    int widthSize = MeasureSpec.getSize(widthMeasureSpec);
    int heightMode = MeasureSpec.getMode(heightMeasureSpec);
    int heightSize = MeasureSpec.getSize(heightMeasureSpec);

    int height;

    //Measure Width
    if (widthMode == MeasureSpec.EXACTLY) {
      //Must be this size
      width = widthSize;
    } else if (widthMode == MeasureSpec.AT_MOST) {
      //Can't be bigger than...
      width = Math.min(desiredWidth, widthSize);
    } else {
      //Be whatever you want
      width = desiredWidth;
    }

    //Measure Height
    if (heightMode == MeasureSpec.EXACTLY) {
      //Must be this size
      height = heightSize;
    } else if (heightMode == MeasureSpec.AT_MOST) {
      //Can't be bigger than...
      height = Math.min(desiredHeight, heightSize);
    } else {
      //Be whatever you want
      height = desiredHeight;
    }

    int childCount = getChildCount();
    for (int i = 0; i < childCount; i++) {
      View child = getChildAt(i);
      ViewGroup.LayoutParams lp = child.getLayoutParams();
      int childWidthSpec = getChildMeasureSpec(widthMeasureSpec, 0, lp.width);
      int childHeightSpec = getChildMeasureSpec(heightMeasureSpec, 0, lp.height);
      child.measure(childWidthSpec, childHeightSpec);
    }
    params = tv_progress.getLayoutParams();
    params.width = ViewGroup.LayoutParams.WRAP_CONTENT;
    params.height = ViewGroup.LayoutParams.MATCH_PARENT;
    tv_progress.setLayoutParams(params);
    height = tv_progress.getMeasuredHeight();
    //MUST CALL THIS
    setMeasuredDimension(width, height);
  }


  private void init(AttributeSet attrs, int defStyleAttr){

    default_text_size = 8;
    //load styled attributes.
    final TypedArray attributes = getContext().getTheme().obtainStyledAttributes(attrs, R.styleable.UpdateProgressBar,
        defStyleAttr, 0);

    mTextSize = attributes.getDimension(R.styleable.UpdateProgressBar_update_text_size, default_text_size);
    mReachedBarColor = attributes.getResourceId(R.styleable.UpdateProgressBar_update_reached_color, default_reached_color);
    mUnreachedBarColor = attributes.getResourceId(R.styleable.UpdateProgressBar_update_unreached_color, default_unreached_color);
    mTextColor = attributes.getColor(R.styleable.UpdateProgressBar_update_text_color, default_text_color);

    setDefaultProgressBar();

    mOffset = px2dip(3);

    attributes.recycle();
  }

  private void setDefaultProgressBar(){
    setBackgroundResource(mUnreachedBarColor);
    tv_progress = new TextView(getContext());
    tv_progress.setTextSize(mTextSize);
    tv_progress.setGravity(Gravity.RIGHT | Gravity.CENTER_VERTICAL);
    tv_progress.setTextColor(mTextColor);
    tv_progress.setLines(1);
    tv_progress.setBackgroundResource(mReachedBarColor);
    tv_progress.setPadding(0,0,5,1);
    tv_progress.setText("0%");
    addView(tv_progress);
  }

  public void setProgress(int progress){
    tv_progress.setText(progress+"%");
    int proWidth = width*progress/100;
    if (tv_progress.getWidth() < proWidth)
      params.width = proWidth;//这里不能填充mOffset,因为是椭圆进度条,填充会导致椭圆宽度被进度条覆盖,导致不美观
    tv_progress.setLayoutParams(params);
  }

  /**
   * 根据手机的分辨率从 dp 的单位 转成为 px(像素)
   */
  public int dip2px(Context context, float dpValue) {
    final float scale = context.getResources().getDisplayMetrics().density;
    return (int) (dpValue * scale + 0.5f);
  }

  /**
   * 根据手机的分辨率从 px(像素) 的单位 转成为 dp
   */
  public int px2dip(float pxValue) {
    final float scale = getContext().getResources().getDisplayMetrics().density;
    return (int) (pxValue / scale + 0.5f);
  }

  /**
   * 将px值转换为sp值,保证文字大小不变
   */
  public int px2sp(float pxValue) {
    final float fontScale = getContext().getResources().getDisplayMetrics().scaledDensity;
    return (int) (pxValue / fontScale + 0.5f);
  }

  /**
   * 将sp值转换为px值,保证文字大小不变
   */
  public int sp2px(float spValue) {
    final float fontScale = getContext().getResources().getDisplayMetrics().scaledDensity;
    return (int) (spValue * fontScale + 0.5f);
  }

}

用法布局文件

<com.progressbar.example.UpdateProgressBar
    xmlns:pro="http://schemas.android.com/apk/res-auto"
    android:id="@+id/progress"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    pro:update_text_size="6sp"
    pro:update_text_color="#FFFFFF"
    pro:update_unreached_color="@drawable/shape_corner_progressbg"
    pro:update_reached_color="@drawable/shape_corner_progressbar"/>

MainActivity

import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.app.AppCompatActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;

import com.progressbar.NumberProgressBar;

import java.util.Timer;
import java.util.TimerTask;


public class MainActivity extends AppCompatActivity {
  private Timer timer;
  private UpdateProgressBar progressBar;
  private int progress;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    progressBar = (UpdateProgressBar)findViewById(R.id.progress);

    timer = new Timer();
    timer.schedule(new TimerTask() {
      @Override
      public void run() {
        runOnUiThread(new Runnable() {
          @Override
          public void run() {
            progress++;
            progressBar.setProgress(progress);
            if(progress == 100) {
              Toast.makeText(getApplicationContext(), getString(R.string.finish), Toast.LENGTH_SHORT).show();
//              progress = 0;
//              progressBar.setProgress(0);
              timer.cancel();
            }
          }
        });
      }
    }, 1000, 100);
  }

  @Override
  public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
  }

  @Override
  public boolean onOptionsItemSelected(MenuItem item) {
    // Handle action bar item clicks here. The action bar will
    // automatically handle clicks on the Home/Up button, so long
    // as you specify a parent activity in AndroidManifest.xml.
    int id = item.getItemId();
    if (id == R.id.action_settings) {
      return true;
    }
    return super.onOptionsItemSelected(item);
  }

  @Override
  protected void onDestroy() {
    super.onDestroy();
    timer.cancel();
  }
}

渐变背景

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">

  <solid android:color="#4984f2"/>

  <gradient
    android:startColor="#4984f2"
    android:endColor="#000" />

  <corners
    android:topLeftRadius="15dp"
    android:topRightRadius="15dp"
    android:bottomLeftRadius="15dp"
    android:bottomRightRadius="15dp"/>
</shape>
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">

  <solid android:color="#dadada"/>

  <gradient
  android:startColor="#FFF"
  android:endColor="#000" />


  <corners
    android:topLeftRadius="15dp"
    android:topRightRadius="15dp"
    android:bottomLeftRadius="15dp"
    android:bottomRightRadius="15dp"/>
</shape>

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


# Android  # Progress  # 解析android中ProgressBar的用法  # android中ProgressDialog与ProgressBar的使用详解  # android ListView和ProgressBar(进度条控件)的使用方法  # Android ProgressBar进度条和ProgressDialog进度框的展示DEMO  # 实例详解Android自定义ProgressDialog进度条对话框的实现  # Android自定义ProgressDialog进度等待框  # Android ProgressBar进度条使用详解  # Android三种方式实现ProgressBar自定义圆形进度条  # Android 自定义ProgressDialog进度条对话框用法详解  # Android ProgressDialog进度条使用详解  # 进度条  # 转换为  # 转成  # 自己的  # 这是  # 有什么  # 都有  # 也没  # 这么多  # 找了  # 自定义  # 第三方  # 大家多多  # 就上  # 想找个  # 各种各样  # getMode  # MeasureSpec  # widthSize  # desiredHeight 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: PHP 实现电台节目表的智能时间匹配与今日/明日轮播逻辑  如何利用DOS批处理实现定时关机操作详解  免费网站制作appp,免费制作app哪个平台好?  Laravel如何发送系统通知_Laravel Notifications实现多渠道消息通知  Laravel Livewire是什么_使用Laravel Livewire构建动态前端界面  Laravel如何集成Inertia.js与Vue/React?(安装配置)  如何快速搭建高效可靠的建站解决方案?  Android okhttputils现在进度显示实例代码  Chrome浏览器标签页分组怎么用_谷歌浏览器整理标签页技巧【效率】  如何在阿里云域名上完成建站全流程?  EditPlus中的正则表达式 实战(2)  Laravel DB事务怎么使用_Laravel数据库事务回滚操作  南京网站制作费用,南京远驱官方网站?  如何在云虚拟主机上快速搭建个人网站?  Win11怎么关闭透明效果_Windows11辅助功能视觉效果设置  Python制作简易注册登录系统  如何在服务器上三步完成建站并提升流量?  Laravel如何使用Contracts(契约)进行编程_Laravel契约接口与依赖反转  Laravel怎么进行数据库回滚_Laravel Migration数据库版本控制与回滚操作  Laravel如何使用Passport实现OAuth2?(完整配置步骤)  如何做网站制作流程,*游戏网站怎么搭建?  消息称 OpenAI 正研发的神秘硬件设备或为智能笔,富士康代工  谷歌浏览器如何更改浏览器主题 Google Chrome主题设置教程  教学论文网站制作软件有哪些,写论文用什么软件 ?  制作无缝贴图网站有哪些,3dmax无缝贴图怎么调?  Laravel怎么自定义错误页面_Laravel修改404和500页面模板  网站制作企业,网站的banner和导航栏是指什么?  Laravel如何实现API版本控制_Laravel版本化API设计方案  1688铺货到淘宝怎么操作 1688一键铺货到自己店铺详细步骤  zabbix利用python脚本发送报警邮件的方法  Laravel如何实现多对多模型关联?(Eloquent教程)  Linux系统运维自动化项目教程_Ansible批量管理实战  文字头像制作网站推荐软件,醒图能自动配文字吗?  使用spring连接及操作mongodb3.0实例  Laravel事件监听器怎么写_Laravel Event和Listener使用教程  网站建设保证美观性,需要考虑的几点问题!  php增删改查怎么学_零基础入门php数据库操作必知基础【教程】  网站页面设计需要考虑到这些问题  Win11怎么修改DNS服务器 Win11设置DNS加速网络【指南】  微信小程序 canvas开发实例及注意事项  免费的流程图制作网站有哪些,2025年教师初级职称申报网上流程?  网站制作报价单模板图片,小松挖机官方网站报价?  详解Nginx + Tomcat 反向代理 如何在高效的在一台服务器部署多个站点  大连企业网站制作公司,大连2025企业社保缴费网上缴费流程?  C语言设计一个闪闪的圣诞树  如何在 Pandas 中基于一列条件计算另一列的分组均值  清除minerd进程的简单方法  百度输入法ai组件怎么删除 百度输入法ai组件移除工具  Linux后台任务运行方法_nohup与&使用技巧【技巧】  北京网站制作的公司有哪些,北京白云观官方网站?