Android自定义View(五)——带扫描线的View

因为技术原理比较简单,所以就不详细赘述实现的细节了。

效果需求
一个具有圆形背景的等宽等高的视图上,上下来回滚动一个渐变的矩形,矩形的两边不能超出圆,也不能比圆小。

遇到的问题
如果只看上面这句话,大家都会觉得很简单,在视图上绘制一个圆,再绘制一个渐变的矩形,控制坐标来移动矩形就好了。但当大家实际操作的时候可能就会遇到这样一个问题:矩形绘制的时候总感觉很不协调,达不到预期效果。为什么呢?因为android默认的视图轮廓都是矩形的,即使背景是个圆,但是轮廓还是矩形,拟绘制的矩形宽度不变的话,就像一根固定的棍子在圆内滚动,还会超出圆的边界;如果动态设置矩形的宽度,矩形的两端还是不能平滑的和圆重叠。

解决的一些思路
1.如果是Android5.0及以上的系统,这个问题很好解决,有一个方法:View.setClipToOutline(boolean clip)或者在xml里android:clipToOutline =boolean,设置成true后,给view设置一个任何形状的背景,画矩形时把矩形的宽度设得比view个宽度大些或者相等,那么绘制的矩形两端就会很平滑的和圆相切,像是被圆的边盖住了一样;

2.如果是Android5.0以下的系统,也不要灰心,我们可以从裁剪Canvas入手。说到底,View的绘制还是在Canvas上面进行的,只要我们能把Canvas裁剪成一个以view的中心为圆心,以view的宽度的一半或高度的一半为半径的圆,那么不管滚动的矩形多宽,也只能绘制在这个圆形的画板上,多月部分被平滑的截掉了,达到了预期效果。

作为一个自定义view新手,可能这些方法对大牛们而言就是小儿科,但是我却花了一天多时间才折腾出来,大家随意看看就好。

效果图
这里写图片描述

代码

/**
 * com.ykb.json.customview
 * 描述 :带扫描线的ImageView
 * 作者 : ykb
 * 时间 : 15/11/4.
 */
public class ScanningImageView extends ImageView {
   

    private static final int CHANGE_BOUNDS = 50;
    private Paint mPaint;
    private int mHeight = 0;
    private Path mPath;

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

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

    public ScanningImageView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            setClipToOutline(true);//设置绘制的覆盖物不能超出背景的轮廓
        }
        mPath = new Path();
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setColor(Color.TRANSPARENT);
        mPaint.setAlpha(255);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        mHeight += 10;
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
            mPath.reset();
            canvas.clipPath(mPath); 
            mPath.addCircle(getWidth() / 2, getHeight() / 2, getWidth() / 2, Path.Direction.CCW);
            canvas.clipPath(mPath, Region.Op.REPLACE);
        }
        LinearGradient linearGradient = new LinearGradient(0, mHeight - CHANGE_BOUNDS, 0, mHeight, new int[]{Color.TRANSPARENT, Color.WHITE}, null, Shader.TileMode.CLAMP);
        mPaint.setShader(linearGradient);
        canvas.drawRect(0, mHeight - CHANGE_BOUNDS, getWidth(), mHeight, mPaint);

        if (mHeight >= getHeight()) {
            mHeight = 0;
        }
        postInvalidateDelayed(40);

        super.onDraw(canvas);
    }
}

======================我是华丽的分割线==========================

因为当时没有适配机型测试,后来发现在三星等手机5.0以下的系统版本上会出现无法裁剪的bug,现在来修正一下以前的做法o(╯□╰)o

1.首先,在5.0以下的手机上,必须把这个视图关闭硬件加速——解决不能正常裁剪的问题;

2.把构造方法里的

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            setClipToOutline(true);//设置绘制的覆盖物不能超出背景的轮廓
        }

去掉;

3.把onDraw方法里的

 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
            mPath.reset();
            canvas.clipPath(mPath); 
            mPath.addCircle(getWidth() / 2, getHeight() / 2, getWidth() / 2, Path.Direction.CCW);
            canvas.clipPath(mPath, Region.Op.REPLACE);
        }

if判断去掉

  @Override
    protected void onDraw(Canvas canvas) {
        mHeight += 10;
        mPath.reset();
        canvas.clipPath(mPath); 
        mPath.addCircle(getWidth() / 2, getHeight() / 2, getWidth() / 2, Path.Direction.CCW);
        canvas.clipPath(mPath, Region.Op.REPLACE);
        LinearGradient linearGradient = new LinearGradient(0, mHeight - CHANGE_BOUNDS, 0, mHeight, new int[]{Color.TRANSPARENT, Color.WHITE}, null, Shader.TileMode.CLAMP);
        mPaint.setShader(linearGradient);
        canvas.drawRect(0, mHeight - CHANGE_BOUNDS, getWidth(), mHeight, mPaint);

        if (mHeight >= getHeight()) {
            mHeight = 0;
        }
        postInvalidateDelayed(
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值