这篇文章的题目不知道该咋起,就暂且这样吧。
这篇博文解决的问题:
这里的布局情况是一个LinearLayout,里头放了两TextView,关键在于,LinearLayout的背景是一个带圆角的,而TextView没有圆角效果是一个直角,所以在头和尾的这两TextView的直角会形成超出父布局期望的范围这种现象。
实际期望的效果:
期望的效果应该是子布局根据父布局背景的圆角大小进行调整,把TextView直角突出的部分给裁剪掉。
要实现这个效果其实很简单,只需要自定义父布局,让父布局根据自己的圆角大小,调整画布,让子View的绘制不要超出画布范围即可。
贴出代码:
public class AutoFixFrameLayout extends LinearLayout {
private int mRadius = 0;
public AutoFixFrameLayout(Context context) {
super(context);
}
public AutoFixFrameLayout(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public AutoFixFrameLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
//or in here
}
public void setRadius(int radius) {
mRadius = radius;
invalidate();
}
@Override
protected void dispatchDraw(Canvas canvas) {
//关键代码在这里
Path path = new Path();
RectF rectF = new RectF();
rectF.set(0, 0, getWidth(), getHeight());
path.addRoundRect(rectF, dp2px(getContext(), mRadius), dp2px(getContext(), mRadius), Path.Direction.CW);
canvas.clipPath(path);
//要在调用super.dispatchDraw之前设置裁切范围噢
super.dispatchDraw(canvas);
}
private int dp2px(Context context, int dp) {
return (int) (context.getResources().getDisplayMetrics().density * dp + 0.5f);
}
}
这个父布局的关键在于,dispatchDraw,在这个方法内,设置了canvas的裁切范围,注意 圆角大小要自己根据实际情况设置,为Path添加了一个圆角RectF,并且设置canvas裁切范围,如此就能实现上图所示的效果了。
再来说说为啥在dispatchDraw设置裁切范围就能对子View生效。
ViewGroup.java
protected void dispatchDraw(Canvas canvas) {
//...省略若干无关代码
drawChild(canvas, transientChild, drawingTime);
....
}
//child.draw 即调用到子View的draw方法中
protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
return child.draw(canvas, this, drawingTime);
}
View.java
public void draw(Canvas canvas) {
//省略若干无关代码...
onDraw(canvas);
....
}
结论:子View拿到的canvas实际上是在ViewGroup的dispatchDraw当中传过来的,那么在dispatchDraw方法内设置canvas的裁切,限定了画布范围,子View的绘制自然就被拿捏了。