android 超级好用的 ProgressBar

直接看效果图:

 

 

 对于android开发来说 ,进度条是非常常见的一个组件,今天公司项目运用到播放gif同时进行进度条。一下子把我给整懵逼,进度条这个倒是很简单,但是要做到上图那样的效果就有点尴尬了。

 我一开始的思路是自定义进度条样式,于是在某度上搜索了一番,结果发现大部分进度条都是要么圆形加载,要么就是更改颜色状态,最终在网上找到一篇这类似的效果的文章开心的不得了。文章路径:https://blog.csdn.net/ahaochina/article/details/52104134

有了这个思路,站在巨人的肩膀上手的也就更快。

只要代码 SaundProgressBar.java 

public class SaundProgressBar extends ProgressBar {
	private Drawable m_indicator;
	private int m_offset = 5;
	private TextPaint m_textPaint;
	private Formatter m_formatter;

	onLoadingCallBackListener onLoadingCallBackListener;
	private String mName=this.getClass().getName();

	public  interface  onLoadingCallBackListener{
		void onLoadingCallBack(ProgressBar progressBar,int dx);
		void onFinish(ProgressBar progressBar);
	}

	public void setOnLoadingCallBackListener(SaundProgressBar.onLoadingCallBackListener onLoadingCallBackListener) {
		this.onLoadingCallBackListener = onLoadingCallBackListener;
	}

	public SaundProgressBar(Context context) {
		this(context, null);
	}

	public SaundProgressBar(Context context, AttributeSet attrs) {
		this(context, attrs, 0);
	}

	public SaundProgressBar(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);

		// create a default progress bar indicator text paint used for drawing
		// the
		// text on to the canvas
		m_textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
		m_textPaint.density = getResources().getDisplayMetrics().density;
		m_textPaint.setColor(Color.WHITE);
		m_textPaint.setTextAlign(Align.CENTER);
		m_textPaint.setTextSize(10);
		m_textPaint.setFakeBoldText(true);

		// get the styleable attributes as defined in the xml
		TypedArray a = context.obtainStyledAttributes(attrs,
				R.styleable.SaundProgressBar, defStyle, 0);

		if (a != null) {
			m_textPaint.setTextSize(a.getDimension(
					R.styleable.SaundProgressBar_textSize, 10));
			m_textPaint.setColor(a.getColor(
					R.styleable.SaundProgressBar_textColor, Color.WHITE));

			int alignIndex = (a.getInt(R.styleable.SaundProgressBar_textAlign,
					1));
			if (alignIndex == 0) {
				m_textPaint.setTextAlign(Align.LEFT);
			} else if (alignIndex == 1) {
				m_textPaint.setTextAlign(Align.CENTER);
			} else if (alignIndex == 2) {
				m_textPaint.setTextAlign(Align.RIGHT);
			}

			int textStyle = (a
					.getInt(R.styleable.SaundProgressBar_textStyle, 1));
			if (textStyle == 0) {
				m_textPaint.setTextSkewX(0.0f);
				m_textPaint.setFakeBoldText(false);
			} else if (textStyle == 1) {
				m_textPaint.setTextSkewX(0.0f);
				m_textPaint.setFakeBoldText(true);
			} else if (textStyle == 2) {
				m_textPaint.setTextSkewX(-0.25f);
				m_textPaint.setFakeBoldText(false);
			}

			m_indicator = a
					.getDrawable(R.styleable.SaundProgressBar_progressIndicator);

			m_offset = (int) a.getDimension(
					R.styleable.SaundProgressBar_offset, 0);

			a.recycle();
		}
	}


	public  void setProgressName(String name) {
		this.mName=name;
	}
	/**
	 * Sets the drawable used as a progress indicator
	 * 
	 * @param indicator
	 */
	public void setProgressIndicator(Drawable indicator) {
		m_indicator = indicator;
	}

	/**
	 * The text formatter is used for customizing the presentation of the text
	 * displayed in the progress indicator. The default text format is X% where
	 * X is [0,100]. To use the formatter you must provide an object which
	 * implements the {@linkplain SaundProgressBar.Formatter} interface.
	 * 
	 * @param formatter
	 */
	public void setTextFormatter(Formatter formatter) {
		m_formatter = formatter;
	}

	/**
	 * The additional offset is for tweaking the position of the indicator.
	 * 
	 * @param offset
	 */
	public void setOffset(int offset) {
		m_offset = offset;
	}

	/**
	 * Set the text color
	 * 
	 * @param color
	 */
	public void setTextColor(int color) {
		m_textPaint.setColor(color);
	}

	/**
	 * Set the text size.
	 * 
	 * @param size
	 */
	public void setTextSize(float size) {
		m_textPaint.setTextSize(size);
	}

	/**
	 * Set the text bold.
	 * 
	 * @param bold
	 */
	public void setTextBold(boolean bold) {
		m_textPaint.setFakeBoldText(true);
	}

	/**
	 * Set the alignment of the text.
	 * 
	 * @param align
	 */
	public void setTextAlign(Align align) {
		m_textPaint.setTextAlign(align);
	}

	/**
	 * Set the paint object used to draw the text on to the canvas.
	 * 
	 * @param paint
	 */
	public void setPaint(TextPaint paint) {
		m_textPaint = paint;
	}

	@Override
	protected synchronized void onMeasure(int widthMeasureSpec,
			int heightMeasureSpec) {
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);

		// if we have an indicator we need to adjust the height of the view to
		// accomodate the indicator
		if (m_indicator != null) {
			final int width = getMeasuredWidth();
			final int height = getMeasuredHeight() + getIndicatorHeight();

			// make the view the original height + indicator height size
			setMeasuredDimension(width, height);
		}
	}

	private int getIndicatorWidth() {
		if (m_indicator == null) {
			return 0;
		}

		Rect r = m_indicator.copyBounds();
		int width = r.width();

		return width;
	}

	private int getIndicatorHeight() {
		if (m_indicator == null) {
			return 0;
		}

		Rect r = m_indicator.copyBounds();
		int height = r.height();

		return height;
	}

	@Override
	protected synchronized void onDraw(Canvas canvas) {
		Drawable progressDrawable = getProgressDrawable();

		// If we have an indicator then we'll need to adjust the drawable bounds
		// for
		// the progress bar and its layers (if the drawable is a layer
		// drawable).
		// This will ensure the progress bar gets drawn in the correct position
		if (m_indicator != null) {
			if (progressDrawable != null
					&& progressDrawable instanceof LayerDrawable) {
				LayerDrawable d = (LayerDrawable) progressDrawable;

				for (int i = 0; i < d.getNumberOfLayers(); i++) {
					d.getDrawable(i).getBounds().top = getIndicatorHeight();

					// thanks to Dave [dave@pds-uk.com] for point out a bug
					// which eats up
					// a lot of cpu cycles. It turns out the issue was linked to
					// calling
					// getIntrinsicHeight which proved to be very cpu intensive.
					d.getDrawable(i).getBounds().bottom = d.getDrawable(i)
							.getBounds().height()
							+ getIndicatorHeight();
				}
			} else if (progressDrawable != null) {
				// It's not a layer drawable but we still need to adjust the
				// bounds
				progressDrawable.getBounds().top = m_indicator
						.getIntrinsicHeight();
				// thanks to Dave[dave@pds-uk.com] -- see note above for
				// explaination.
				progressDrawable.getBounds().bottom = progressDrawable
						.getBounds().height() + getIndicatorHeight();
			}
		}

		// update the size of the progress bar and overlay
		updateProgressBar();

		super.onDraw(canvas);
		//获取当前进度条的x轴
		canvas.save();
		int dx = 0;
		// get the position of the progress bar's right end
		if (progressDrawable != null
				&& progressDrawable instanceof LayerDrawable) {
			LayerDrawable d = (LayerDrawable) progressDrawable;
			Drawable progressBar = d.findDrawableByLayerId(R.id.progress);
			dx = progressBar.getBounds().right;
		} else if (progressDrawable != null) {
			dx = progressDrawable.getBounds().right;
		}
		// adjust for any additional offset
		dx = dx - getIndicatorWidth() / 2 - m_offset + getPaddingLeft();
		// translate the canvas to the position where we should draw the
		// indicator
		canvas.translate(dx, 0);

		// 绘制上方进度指示器
		// bar
		if (m_indicator != null) {
			m_indicator.draw(canvas);
			canvas.drawText(
					m_formatter != null ? m_formatter.getText(getProgress())
							: Math.round(getScale(getProgress()) * 100.0f)
									+ "%", getIndicatorWidth() / 2,
					getIndicatorHeight() / 2 + 1, m_textPaint);
			// restore canvas to original
			canvas.restore();
		}
		//当前进度条回调
		if(getProgress()>=getMax()){
			if(onLoadingCallBackListener!=null){
				onLoadingCallBackListener.onFinish(this);
			}
		}else if(onLoadingCallBackListener!=null){
			onLoadingCallBackListener.onLoadingCallBack(this,dx);
		}
	}

	@Override
	public synchronized void setProgress(int progress) {
		super.setProgress(progress);

		// the setProgress super will not change the details of the progress bar
		// anymore so we need to force an update to redraw the progress bar
		invalidate();
	}

	private float getScale(int progress) {
		float scale = getMax() > 0 ? (float) progress / (float) getMax() : 0;

		return scale;
	}

	/**
	 * Instead of using clipping regions to uncover the progress bar as the
	 * progress increases we increase the drawable regions for the progress bar
	 * and pattern overlay. Doing this gives us greater control and allows us to
	 * show the rounded cap on the progress bar.
	 */
	private void updateProgressBar() {
		Drawable progressDrawable = getProgressDrawable();

		if (progressDrawable != null
				&& progressDrawable instanceof LayerDrawable) {
			LayerDrawable d = (LayerDrawable) progressDrawable;

			final float scale = getScale(getProgress());

			// get the progress bar and update it's size
			Drawable progressBar = d.findDrawableByLayerId(R.id.progress);

			final int width = d.getBounds().right - d.getBounds().left;

			if (progressBar != null) {
				Rect progressBarBounds = progressBar.getBounds();
				progressBarBounds.right = progressBarBounds.left
						+ (int) (width * scale + 0.5f);
				progressBar.setBounds(progressBarBounds);
			}

			// get the pattern overlay
			Drawable patternOverlay = d.findDrawableByLayerId(R.id.pattern);

			if (patternOverlay != null) {
				if (progressBar != null) {
					// we want our pattern overlay to sit inside the bounds of
					// our progress bar
					Rect patternOverlayBounds = progressBar.copyBounds();
					final int left = patternOverlayBounds.left;
					final int right = patternOverlayBounds.right;

					patternOverlayBounds.left = (left + 1 > right) ? left
							: left + 1;
					patternOverlayBounds.right = (right > 0) ? right - 1
							: right;
					patternOverlay.setBounds(patternOverlayBounds);
				} else {
					// we don't have a progress bar so just treat this like the
					// progress bar
					Rect patternOverlayBounds = patternOverlay.getBounds();
					patternOverlayBounds.right = patternOverlayBounds.left
							+ (int) (width * scale + 0.5f);
					patternOverlay.setBounds(patternOverlayBounds);
				}
			}
		}
	}

	/**
	 * You must implement this interface if you wish to present a custom
	 * formatted text to be used by the Progress Indicator. The default format
	 * is X% where X [0,100]
	 * 
	 * @author jsaund
	 * 
	 */
	public interface Formatter {
		public String getText(int progress);
	}
}

 

在这类里面添加了一个接口回调,进行播放gif动画及移动gif 的view ,

主要回调原理,是根据当前绘制的进度进行回调的,同时将dx 值通过  mActivity_gif_giv.setTranslationX(dx);实现位移效果

获取当前进度条x轴

	//获取当前进度条的x轴
		canvas.save();
		int dx = 0;
		// get the position of the progress bar's right end
		if (progressDrawable != null
				&& progressDrawable instanceof LayerDrawable) {
			LayerDrawable d = (LayerDrawable) progressDrawable;
			Drawable progressBar = d.findDrawableByLayerId(R.id.progress);
			dx = progressBar.getBounds().right;
		} else if (progressDrawable != null) {
			dx = progressDrawable.getBounds().right;
		}
		// adjust for any additional offset
		dx = dx - getIndicatorWidth() / 2 - m_offset + getPaddingLeft();
		// translate the canvas to the position where we should draw the
		// indicator
		canvas.translate(dx, 0);

 

这里dx 就是当前x轴 ,只要将这个值回调,给自己需要的移动的View就行了。

 

忘记说了这里播放动画用的是第三方库:pl.droidsonroids.gif:android-gif-drawable:1.2.11

 

xml布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <pl.droidsonroids.gif.GifImageView
        android:id="@+id/activity_gif_giv"
        android:layout_width="30dp"
        android:layout_height="50dp"
        android:layout_marginLeft="20dp"
        android:layout_marginRight="20dp"
        android:layout_marginTop="50dp"
        android:src="@drawable/loading" />


    <com.xiangjiale.saunprogressbar.widget.SaundProgressBar
        android:id="@+id/pb_downloading"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="20dp"
        android:layout_marginRight="20dp"
        style="@style/Widget.ProgressBar.RegularProgressBar"
        android:layout_marginBottom="32dp"
        app:offset="10dp"
        app:textSize="10sp"
        />

    <com.xiangjiale.saunprogressbar.widget.SaundProgressBar
        android:id="@+id/pb_downloading2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="20dp"
        android:layout_marginRight="20dp"
        style="@style/Widget.ProgressBar.RegularProgressBar"
        android:layout_marginBottom="32dp"
        android:layout_marginTop="50dp"
        app:offset="10dp"
        app:textSize="10sp"
        />

</LinearLayout>

github路径: https://github.com/zqMyself/SuperSaundProgressBar

发布了12 篇原创文章 · 获赞 3 · 访问量 6972
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览