自定义带阴影和圆角效果的布局

开发项目的时候经常会用到一些带有阴影或者圆角效果的布局,通常都会使用shape文件实现这些效果。但是如果app中多个布局都需要有阴影或者圆角效果,并且样式又都不太一样,总不能为每套样式都写一个shape文件吧,这样就太麻烦了。本着使用简单并且可复用的原则,结合自定义控件自己琢磨了一个可以自己控制阴影和圆角效果的布局。

  1. 定义attrs.xml
<resources>
    <declare-styleable name="MyViewGroup">
        <attr name="shadowColor" format="color"/>
        <attr name="bgColor" format="color"/>
        <attr name="shadowRadius" format="dimension"/>
        <attr name="roundRadius" format="dimension"/>
    </declare-styleable>
</resources>
  1. 获取属性值
private void getAttrValues(Context context,AttributeSet attrs){
        TypedArray array = context.obtainStyledAttributes(attrs,R.styleable.MyViewGroup);
        shadowColor = array.getColor(R.styleable.MyViewGroup_shadowColor, Color.parseColor("#33000000"));
        bgColor = array.getColor(R.styleable.MyViewGroup_bgColor, Color.parseColor("#33000000"));
        shadowRadius = array.getDimension(R.styleable.MyViewGroup_shadowRadius,5.0f);
        roundRadius = array.getDimension(R.styleable.MyViewGroup_roundRadius,5.0f);
        array.recycle();
        init();
    }
  1. 初始化画笔
 private void init(){
        setLayerType(LAYER_TYPE_SOFTWARE,null);//关闭硬件加速
        setWillNotDraw(ture);//不执行onDraw
        paint = new Paint();
        paint.setColor(bgColor);
        paint.setShadowLayer(shadowRadius,0,0,shadowColor);//设置圆角和阴影
    }
  1. 重写dispatchDraw,完成绘制
@Override
    protected void dispatchDraw(Canvas canvas) {
        canvas.drawRoundRect(new RectF(shadowRadius,shadowRadius,getMeasuredWidth()-shadowRadius,getMeasuredHeight()-shadowRadius),roundRadius,roundRadius,paint);
        canvas.clipPath(path, Region.Op.INTERSECT);
        super.dispatchDraw(canvas);
    }

之所以没有在onDraw中重写,是因为viewGroup一般不会执行onDraw,但是dispatchDraw会执行,并且可以避免子控件覆盖viewgroup的问题,关于dispatchDraw和onDraw的区别,可以参考我的另外一篇文章《自定义ViewGroup中dispatchDraw和onDraw的区别》

  1. 重写 onSizeChanged计算宽高
 @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        path = new Path();
        path.reset();
        path.addRoundRect(new RectF(shadowRadius,shadowRadius,getMeasuredWidth()-shadowRadius,getMeasuredHeight()-shadowRadius),roundRadius,roundRadius,Path.Direction.CW);
    }
  1. 完整代码
public class MyViewGroup extends LinearLayout {
    private int shadowColor;
    private float shadowRadius;
    private float roundRadius;
    private int bgColor;

    private Paint paint;
    private Path path;
    public MyViewGroup(Context context) {
        super(context);
        getAttrValues(context,null);
    }

    public MyViewGroup(Context context, AttributeSet attrs) {
        super(context, attrs);
        getAttrValues(context,attrs);
    }

    public MyViewGroup(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        getAttrValues(context,attrs);
    }

    public MyViewGroup(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    private void getAttrValues(Context context,AttributeSet attrs){
        TypedArray array = context.obtainStyledAttributes(attrs,R.styleable.MyViewGroup);
        shadowColor = array.getColor(R.styleable.MyViewGroup_shadowColor, Color.parseColor("#33000000"));
        bgColor = array.getColor(R.styleable.MyViewGroup_bgColor, Color.parseColor("#33000000"));
        shadowRadius = array.getDimension(R.styleable.MyViewGroup_shadowRadius,5.0f);
        roundRadius = array.getDimension(R.styleable.MyViewGroup_roundRadius,5.0f);
        array.recycle();
        init();
    }

    private void init(){
        setLayerType(LAYER_TYPE_SOFTWARE,null);
        setWillNotDraw(false);
        paint = new Paint();
        paint.setColor(bgColor);
        paint.setShadowLayer(shadowRadius,0,0,shadowColor);
    }

    @Override
    protected void dispatchDraw(Canvas canvas) {

        canvas.drawRoundRect(new RectF(shadowRadius,shadowRadius,getMeasuredWidth()-shadowRadius,getMeasuredHeight()-shadowRadius),roundRadius,roundRadius,paint);
        canvas.clipPath(path, Region.Op.INTERSECT);
        super.dispatchDraw(canvas);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        path = new Path();
        path.reset();
        path.addRoundRect(new RectF(shadowRadius,shadowRadius,getMeasuredWidth()-shadowRadius,getMeasuredHeight()-shadowRadius),roundRadius,roundRadius,Path.Direction.CW);
    }
}
  1. 布局文件中使用
<com.henkun.mylinnearlayout.MyViewGroup
        android:layout_width="300dp"
        android:layout_height="300dp"
        app:shadowColor="@color/colorPrimary"
        app:shadowRadius="10dp"
        app:roundRadius="10dp"
        app:bgColor="#ffffff"
        android:gravity="center"
        android:layout_centerInParent="true">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="TEST"
            android:textColor="#000000"
            android:layout_gravity="center"/>
    </com.henkun.mylinnearlayout.MyViewGroup>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值