過去因爲設計溼的吹毛求疵,每每不得很少作不少工做。好比下面的這張圖片,很典型的按鈕背景圖片,通常Android會處理成.9文件以供項目使用。
但事情每每沒有這麼簡單,需求會要求在不一樣的地方高度不一致,這個時候.9文件的弱點就出現了。
咱們拿到UI那邊的標註以及切圖時,會默認高度是不會拉伸或者壓縮的,下面截圖中右中爲指望效果。
可是若是咱們在應用中使用同一張.9圖,就不能確保圖片是否會高度拉伸。做爲替代方案,只能讓UI配合給出N套不一樣高度的.9文件進行適配。
上面這種解決方案無形之中增大了安裝包的大小,之前見識過使用xml定義shape實現圓角矩形的示例,能夠考慮使用代碼動態生成Drawable對象,處理好左右兩邊的圓角弧度便可。
xml的shape屬性對應於ShapeDrawable對象,
下面給出ShapeDrawable結合RoundRectShape生成圓角矩形的範例
int outRadius = 100;
int innerRadius = 0;
/*圓角矩形*/
float[] outerRadii = {outRadius, outRadius, 0, 0, 0, 0, outRadius, outRadius};//左上x2,右上x2,右下x2,左下x2,注意順序(順時針依次設置)
int spaceBetOutAndInner = outRadius - innerRadius;//內外矩形間距
RectF inset = new RectF(spaceBetOutAndInner, spaceBetOutAndInner, spaceBetOutAndInner, spaceBetOutAndInner);
float[] innerRadii = {innerRadius, innerRadius, 0, 0, 0, 0, 0, 0};//內矩形 圓角半徑
RoundRectShape roundRectShape = new RoundRectShape(outerRadii, inset, innerRadii);
ShapeDrawable drawable = new ShapeDrawable(roundRectShape);
drawable.getPaint().setColor(Color.RED);
drawable.getPaint().setAntiAlias(true);
drawable.getPaint().setStyle(Paint.Style.FILL);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
btnActmain.setBackground(drawable);
} else {
btnActmain.setBackgroundDrawable(drawable);
}
查看RoundRectShape源碼可知,其在構造函數中傳入內外矩形的圓角半徑以及內外矩形間距,由於咱們這裏的圓角半徑須要根據drawable的高度動態修改,查看父類RectShape源碼有
protect 類型的
rect()方法實現,
/**
* Returns the RectF that defines this rectangle's bounds.
*/
protected final RectF rect() {
return mRect;
}
因此
修改
RoundRectShape的
構造函數,將傳入參數延遲初始化。
另觀察
RectShape
得知在
onResize中進行
mRect的初始化,所以咱們選擇在調用父類的onResize以後,傳入原
RoundRectShape構造方法的相關參數。
@Override
protected void onResize(float width, float height) {
mRect.set(0, 0, width, height);
}
最後,看看自定義CircleArcRectangleShape類的源碼實現,咱們讓其繼承至RectShape,並將RoundRectShape的源碼複製過來,主體修改
部分
以下(其中,clone()方法須要修改一下返回值,這裏不予貼出):
**
* @Description:
* @author: Xiaoxuan948
* @date: 2016/8/23 9:41
*/
public class CircleArcRectangleShape extends RectShape {
private final UtilsLog lg = UtilsLog.getLogger(CircleArcRectangleShape.class);
//修改構造函數
public CircleArcRectangleShape() {
mPath = new Path();
}
//修改onResize方法
@Override
protected void onResize(float w, float h) {
super.onResize(w, Math.min(w, h));//表示在高大於寬時,默認顯示爲圓形
initCircleArcRectangleRadius();//onResize中添加這一句便可
RectF r = rect();
mPath.reset();
if (mOuterRadii != null) {
mPath.addRoundRect(r, mOuterRadii, Path.Direction.CW);
} else {
mPath.addRect(r, Path.Direction.CW);
}
if (mInnerRect != null) {
mInnerRect.set(r.left + mInset.left, r.top + mInset.top,
r.right - mInset.right, r.bottom - mInset.bottom);
if (mInnerRect.width() < w && mInnerRect.height() < h) {
if (mInnerRadii != null) {
mPath.addRoundRect(mInnerRect, mInnerRadii, Path.Direction.CCW);
} else {
mPath.addRect(mInnerRect, Path.Direction.CCW);
}
}
}
}
private void initCircleArcRectangleRadius() {
float outRadius = rect().height();
float innerRadius = outRadius;//建議設置成與outRadius一致,可防止內外矩形覆蓋異常
float spaceBetOutAndInner = rect().height() / 2 - 1;//內外環的間距,這樣設置會使得中間存在一根白線區域
lg.e("initCircleArcRectangleRadius", outRadius, innerRadius, spaceBetOutAndInner);
float[] outerRadii = {outRadius, outRadius, outRadius, outRadius, outRadius, outRadius, outRadius, outRadius};//左上x2,右上x2,右下x2,左下x2,注意順序(順時針依次設置)
RectF inset = new RectF(spaceBetOutAndInner, spaceBetOutAndInner, spaceBetOutAndInner, spaceBetOutAndInner);
float[] innerRadii = {innerRadius, innerRadius, innerRadius, innerRadius, innerRadius, innerRadius, innerRadius, innerRadius};//內矩形圓角半徑
mOuterRadii = outerRadii;
mInset = inset;
mInnerRadii = innerRadii;
if (inset != null) {
mInnerRect = new RectF();
}
}
}
之後調用下面的代碼,系統將自動根據View的高度生成左右爲圓角的按鈕背景圖片,一套代碼完美替換冗餘的資源文件。
ShapeDrawable drawable = new ShapeDrawable(new CircleArcRectangleShape ());