Android自定义View:模仿Lofter图片加载(一)

前言

最近公司给了个需求,要求图片加载的时候显示加载进度。恰好,平时都比较喜欢用Lofter浏览一些图片,所以就有了个想法,就做个模仿Lofter图片加载的控件吧。

先看一下效果图

LofterImageView整体效果

可能上面的图网速太快,看不了什么效果,下面的图应该可以看清楚一点


Android自定义View:模仿Lofter图片加载(一)_第1张图片
LofterImageView控件效果

分析

什么都别说,先看看Lofter加载图片的截图,仔细分析一下如果是我们来实现的话,应该怎么做。


Android自定义View:模仿Lofter图片加载(一)_第2张图片
Lofter加载图片分析.png
  • 首先显示加载进度框
  • 接着图片加载完后支持缩放图片
  • 支持多图滑动预览

只有这三步,仅此而已;那这篇文章首先来分析实现加载进度框,也就是要写好LofterProgressView这个控件

自定义 ProgressBar

老规矩,先仔细分析一下Lofter的ProgressBar,上图

Android自定义View:模仿Lofter图片加载(一)_第3张图片
Lofter的ProgressBar分析

这个ProgressBar控件有三个部分构成

  • 背景:一个圆角矩形
  • 进度条:一条圆弧
  • 百分比:纯文字,没什么特别的

So,我们一步步来实现

首先,为了代码的统一,先定义两个私有方法(获取自定义配置initAttrs()、初始化画笔initProSettings()),在构造函数中执行这两个方法。

 public LofterProgressView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        //先获取自定义的配置
        initAttrs(context, attrs);
        //再进行初始化相关的配置
        initProSettings();
    }
Step 1 绘制圆角矩形背景

背景这里我定义了三个配置项,宽度、颜色以及圆角的半径

mBgWidth = typedArray.getDimensionPixelSize(R.styleable.ProgressView_bgWidth, 100);
mBgColor = typedArray.getColor(R.styleable.ProgressView_bgColor, Color.WHITE);
mBgCornerRadius = typedArray.getDimensionPixelSize(R.styleable.ProgressView_bgCornerRadius, 20);

初始化画笔也没什么特别的,仅仅设置了颜色和填充模式而已

mBgPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mBgPaint.setColor(mBgColor);
mBgPaint.setStyle(Paint.Style.FILL);

接下来就要画矩形了,但是前提是要清楚矩形具体要画在哪里,也就是说要知道坐标的位置onDraw()onMeasure()中都不建议创建对象,因此我们在LofterProgressView这个控件中创建mBgRect的成员变量,并在initProSettings()方法中将这个创建RectF对象并赋给mBgRect

mBgRect = new RectF();

而在onMeasure()中,我们只要设置一下矩形的坐标即可

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    //中心的位置
    centerX = getMeasuredWidth() / 2;
    centerY = getMeasuredHeight() / 2;

    //计算并设置好bg圆角矩形的位置
    mBgRect.set(centerX - (mBgWidth / 2), centerY - (mBgWidth / 2), centerX + (mBgWidth / 2), centerY + (mBgWidth / 2));
    ...
}

最后,在onDraw()中使用drawRoundRect(),传入设置好坐标的矩形、圆角的xy轴半径以及画笔,就可以绘制圆角矩形背景了

//画背景,圆角矩形
canvas.drawRoundRect(mBgRect, mBgCornerRadius, mBgCornerRadius, mBgPaint);

背景的效果图就出来了


Android自定义View:模仿Lofter图片加载(一)_第4张图片
LofterProgressView_bg.png
Step 2 绘制进度条圆弧

看下图,绘制圆弧这里有两个步骤:

  • 圆环背景(静态,也就是进度为0的状态显示)
  • 进度圆环(动态)


    Android自定义View:模仿Lofter图片加载(一)_第5张图片
    进度条圆弧绘制分析

圆弧这里我定义了四个配置项,半径、静态圆环颜色、进度条圆弧颜色以及进度条圆弧的宽度

mInnerRadius = typedArray.getDimensionPixelSize(R.styleable.ProgressView_innerRadius, 50);
mEdgeColor = typedArray.getColor(R.styleable.ProgressView_edgeColor, Color.RED);
mRingColor = typedArray.getColor(R.styleable.ProgressView_ringColor, Color.BLUE);
mRingWidth = typedArray.getDimensionPixelSize(R.styleable.ProgressView_ringWidth, 10);

初始化画笔

//静态圆环背景画笔
mEdgePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mEdgePaint.setColor(mEdgeColor);
mEdgePaint.setStrokeCap(Paint.Cap.ROUND);
mEdgePaint.setStrokeWidth(mRingWidth);
mEdgePaint.setStyle(Paint.Style.STROKE);
//动态进度条圆弧画笔
mPercentPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPercentPaint.setColor(mPercentColor);
mPercentPaint.setStyle(Paint.Style.FILL);
mPercentPaint.setTextSize(mPercentSize);

下面就先绘制静态的圆环,比较简单

 //画静态圆环,相当于进度为0时候的显示
canvas.drawCircle(centerX, centerY, mInnerRadius, mEdgePaint);

第二就要绘制进度圆弧了,绘制圆弧需要用到它对应的外切矩形,就是恰好包着圆弧所在圆的矩形,在的代码里面就是RectF这个类。因此,我们需要在onMeasure()中确定矩形的坐标。

//圆弧外切的矩形(在)
private RectF mOval;

/**
 * 初始化配置
 */
private void initProSettings(){
    ...
    mOval = new RectF();
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    centerX = getMeasuredWidth() / 2;
    centerY = getMeasuredHeight() / 2;

    ...
    //计算外切矩形的位置
    mOval.left = (centerX - mInnerRadius);
    mOval.top = (centerY - mInnerRadius);
    mOval.right = centerX + mInnerRadius;
    mOval.bottom = centerY + mInnerRadius;
}

外切的矩形只是确定了圆弧所在的圆,但是这个圆弧究竟要画多少(或者说这个这个圆弧究竟要占整个圆的多少,几分之几呢),这里需要计算出来的是圆弧扫过的角度。


/**
 * mPercent是指下载进度
 * 圆,一周是360度
 * 这里圆弧扫过的角度必须要乘以360
 */
progress = (float) mPercent / 100 * 360;

最后就是绘制进度了

//画进度条圆环
//第二个参数是指圆弧的起点在哪,这里是以3点钟方向为0度,因此我们这里写-90
//第三个参数true的意思就是要将圆弧与圆心连起来,也就是话一个扇形,画一个饼,这里我们不需要,设置为false
canvas.drawArc(mOval, -90, progress, false, mRingPaint);

上效果图(为了更显眼,进度条颜色我换了另外的颜色)

Android自定义View:模仿Lofter图片加载(一)_第6张图片
圆弧效果
Step 3 绘制百分比文字

文字这里定义了两个配置项,颜色和大小

mPercentColor = typedArray.getColor(R.styleable.ProgressView_percentColor, Color.GRAY);
mPercentSize = typedArray.getDimensionPixelSize(R.styleable.ProgressView_percentSize, 30);

初始化画笔

//字体的画笔
mPercentPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPercentPaint.setColor(mPercentColor);
mPercentPaint.setStyle(Paint.Style.FILL);
mPercentPaint.setTextSize(mPercentSize);

//计算字体的高度
Paint.FontMetrics fm = mPercentPaint.getFontMetrics();
mTextHeight = (int) Math.ceil(fm.descent - fm.ascent);

绘制字体(先调整一下文字的位置,使文字处于中间的位置)

//计算字体的宽度
mTextWidth = mPercentPaint.measureText(percentText, 0, percentText.length());
 //画百分比
canvas.drawText(percentText, centerX - mTextWidth / 2, centerY + mTextHeight / 4, mPercentPaint);

最后,整个效果图就是这样了

Android自定义View:模仿Lofter图片加载(一)_第7张图片
LofterProgressView控件
Step 4 暴露接口给外部

这里只需要注意重绘就可以了

/**
 * 直接从外部设置百分比
 *
 * @param percent 百分比
 */
 public void setPercent(int percent) {
     this.mPercent = percent;
     //重绘
     postInvalidate();
 }
最后 模拟一下进度显示

xml 配置


模拟下载图片

btnStart.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 101; i++) {
                    try {
                        lofterProgressView.setPercent(i);
                        Thread.sleep(50);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();
    }
});

最终自定义的ProgressBar(LofterProgressView)完成

Android自定义View:模仿Lofter图片加载(一)_第8张图片
最终自定义ProgressBar

附项目地址

  • 【Github地址】

  • 【本篇文章所讲控件 LofterProgressView】


谢谢阅读

下一篇文章,我将会结合Glide和本篇文章的ImageProgressView做一个带进度的图片预览控件。

你可能感兴趣的:(Android自定义View:模仿Lofter图片加载(一))