开发项目的时候经常会用到一些带有阴影或者圆角效果的布局,通常都会使用shape文件实现这些效果。但是如果app中多个布局都需要有阴影或者圆角效果,并且样式又都不太一样,总不能为每套样式都写一个shape文件吧,这样就太麻烦了。本着使用简单并且可复用的原则,结合自定义控件自己琢磨了一个可以自己控制阴影和圆角效果的布局。
- 定义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>
- 获取属性值
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(ture);//不执行onDraw
paint = new Paint();
paint.setColor(bgColor);
paint.setShadowLayer(shadowRadius,0,0,shadowColor);//设置圆角和阴影
}
- 重写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的区别》
- 重写 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);
}
- 完整代码
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);
}
}
- 布局文件中使用
<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>