你可能会需要的UI(一)

前言

打算自己维护一个日常开发会需要用到的UI锦集,方便快(tou)速(lan)完成产品的需求,每一个UI网上很可能都有轮子,这里只是记录笔者自己的实现思路,细节暂时不予深度优化(^__^),例如自定义控件手机旋转的onSaveInstanceState,内存的回收等等,争取每个UI都写一篇博客作为记录,应该不会烂尾吧

滑稽

SimpleUI_GitHub地址

开篇_自定义ImageView

关于圆角ImageView的开源框架已经很多了,有基于BitmapShader实现的,也有基于ProterDuff实现的。

BitmapShader:通过ScaleType设置不同的Matrix,进行的图片的位移缩放策略,然后将Matrix设置进入BitmapShader,然后在Paint设置BitmapShader,然后在Canvas上用这只加了特技的画笔绘制一个圆,DUANG,圆角ImageView就出来了。
ProterDuff:如果说BitmapShader是在绘制时加特技,那么ProterDuff就是在原生ImageView绘制完毕后在上面再次绘制,如果还是要绘制圆角的话,在上面再次绘制一个矩形,比如PorterDuff.Mode.SRC_IN,但是由于是属于过度绘制,一般这种做法实现圆角比较少。

在开发时偶尔会遇到一些需求,局部圆角的ImageView,可能有同学说,哎我用CardView不就好了,然而不幸的是在5.0以下CardView不支持超出部分自动裁剪。CardView的用法

这里写图片描述
笔者整理了下除去PorterDuff还大约有3种ImageView裁剪方案

1.Android L的ViewOutlineProvider
 if (Build.VERSION.SDK_INT >= LOLLIPOP) {  
            imageview.setOutlineProvider(new ViewOutlineProvider() {
                @Override
                public void getOutline(View view, Outline outline) {
                    if (Build.VERSION.SDK_INT >= LOLLIPOP) {
                        outline.setOval(0, 0, circleL.getMeasuredWidth(), circleL.getMeasuredHeight());
                    }
                }
            });
            imageview.setClipToOutline(true);
        }

因为是5.0+的限定方法,跳进去一看,发现底层是借助RenderNode完成硬件渲染╮(╯▽╰)╭至此第一个方案是没办法用了

2.在ImageView调用onDraw的时候把Canvas裁掉一部分

甚至还能裁掉任意的Path,canvas.clipPath(Path path)
细心的同学会发现边缘出现了明显的颗粒化,然而这是底层的锯齿问题,笔者在测试的时候加上了canvas.setDrawFilter(new PaintFlagsDrawFilter(0,Paint.FILTER_BITMAP_FLAG|Paint.ANTI_ALIAS_FLAG));也没有解决问题
这里写图片描述

3.BitmapShader绘制Path

上面也提到了,我们吧要绘制的Drawable通过BitmapShader载入画笔中,在绘制一个我们想要的图形就可以了,至于ImageView显示图片的ScaleType我们可以直接从源码中把CENTER_CROP的Matrix操作copy下来,有兴趣的同学可以了解下ImageView的源码,无非就是一些缩放,位移操作

 private void configureBounds() {
        if (mDrawable == null || !mHaveFrame) {
            return;
        }

        int dwidth = mDrawableWidth;
        int dheight = mDrawableHeight;

        int vwidth = getWidth() - mPaddingLeft - mPaddingRight;
        int vheight = getHeight() - mPaddingTop - mPaddingBottom;

        boolean fits = (dwidth < 0 || vwidth == dwidth) &&
                       (dheight < 0 || vheight == dheight);

        if (dwidth <= 0 || dheight <= 0 || ScaleType.FIT_XY == mScaleType) {
            /* If the drawable has no intrinsic size, or we're told to
                scaletofit, then we just fill our entire view.
            */
            mDrawable.setBounds(0, 0, vwidth, vheight);
            mDrawMatrix = null;
        } else {
            // We need to do the scaling ourself, so have the drawable
            // use its native size.
            mDrawable.setBounds(0, 0, dwidth, dheight);

            if (ScaleType.MATRIX == mScaleType) {
                // Use the specified matrix as-is.
                if (mMatrix.isIdentity()) {
                    mDrawMatrix = null;
                } else {
                    mDrawMatrix = mMatrix;
                }
            } else if (fits) {
                // The bitmap fits exactly, no transform needed.
                mDrawMatrix = null;
            } else if (ScaleType.CENTER == mScaleType) {
                // Center bitmap in view, no scaling.
                mDrawMatrix = mMatrix;
                mDrawMatrix.setTranslate(Math.round((vwidth - dwidth) * 0.5f),
                                         Math.round((vheight - dheight) * 0.5f));
            } else if (ScaleType.CENTER_CROP == mScaleType) {
                mDrawMatrix = mMatrix;

                float scale;
                float dx = 0, dy = 0;

                if (dwidth * vheight > vwidth * dheight) {
                    scale = (float) vheight / (float) dheight; 
                    dx = (vwidth - dwidth * scale) * 0.5f;
                } else {
                    scale = (float) vwidth / (float) dwidth;
                    dy = (vheight - dheight * scale) * 0.5f;
                }

                mDrawMatrix.setScale(scale, scale);
                mDrawMatrix.postTranslate(Math.round(dx), Math.round(dy));
            } else if (ScaleType.CENTER_INSIDE == mScaleType) {
                mDrawMatrix = mMatrix;
                float scale;
                float dx;
                float dy;

                if (dwidth <= vwidth && dheight <= vheight) {
                    scale = 1.0f;
                } else {
                    scale = Math.min((float) vwidth / (float) dwidth,
                            (float) vheight / (float) dheight);
                }

                dx = Math.round((vwidth - dwidth * scale) * 0.5f);
                dy = Math.round((vheight - dheight * scale) * 0.5f);

                mDrawMatrix.setScale(scale, scale);
                mDrawMatrix.postTranslate(dx, dy);
            } else {
                // Generate the required transform.
                mTempSrc.set(0, 0, dwidth, dheight);
                mTempDst.set(0, 0, vwidth, vheight);

                mDrawMatrix = mMatrix;
                mDrawMatrix.setRectToRect(mTempSrc, mTempDst, scaleTypeToScaleToFit(mScaleType));
            }
        }
    }

简单来用的话我们可以抽象一个View出来,让子类实现Path,父类只要负责绘制就行了,笔者以前见过局部圆角矩形ImageView的一个实现方法:通过Layout布局遮罩和设置偏移。。。当我们采用方案3的实现思路甚至能够支持svg转换的Path,笔者这里就不尝试了。
这里写图片描述

自定义ImageView的代码

我感谢那给我力量的我们主基督耶稣,因他以我有忠心,派我服侍他。我从前是亵渎 神的,逼迫人的,侮慢人的;然而我还蒙了怜悯,因我是不信不明白的时候而做的。 (提摩太前书 1:12-13 和合本)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值