android如何給整個檢視view圓角顯示
關於如何給一個view設定圓角,有哪些方法呢?
1.給該view設定一個圓角的背景,這是最常見的用法。如以下程式碼:
round_bg.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<corners android:radius="40dp" />
<solid android:color="#33ff0000" />
</shape >
- 1
- 2
- 3
- 4
- 5
- 6
- 7
這是給view設定40dp的圓角
<android.support.v7.widget.RecyclerView
android:id="@+id/rv_list_1"
android:layout_width="150dp"
android:layout_height="150dp"
android:layout_margin="20dp"
android:background="@drawable/round_bg" />
- 1
- 2
- 3
- 4
- 5
- 6
效果如圖:
這種方式,正常情況下是沒有問題的,可是如果想實現無縫的圓角顯示,例如,它裡面的一個列表,緊貼著邊緣,即padding為0,會發現,圓角的那部分割槽域,還是有子view在顯示的,並沒有完全的實現真正的圓角,因為只是外層的背景圓角了而已。
那有什麼辦法讓子view也圓角顯示呢?下面說下第二種方法。
2.通過程式碼設定圓角,如下:
/**
* 設定檢視裁剪的圓角半徑
* @param radius
*/
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public static void setClipViewCornerRadius(View view, final int radius){
if(Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP){
//不支援5.0版本以下的系統
return ;
}
if(view == null) return;
if(radius <= 0){
return;
}
/*view.setOutlineProvider(new ViewOutlineProvider() {
@Override
public void getOutline(View view, Outline outline) {
outline.setRoundRect(view.getLeft(), view.getTop(), view.getRight(), view.getBottom(), radius);
}
});*/
view.setOutlineProvider(new ViewOutlineProvider() {
@Override
public void getOutline(View view, Outline outline) {
outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), radius);
}
});
view.setClipToOutline(true);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
這是5.0版本之後新增的設定view邊緣的方法,不支援5.0以下版本。
那有沒更合適的方法呢,所幸,5.0版本之後,增加了新的元件,CardView,它可以設定圓角,陰影等。
<android.support.v7.widget.CardView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_margin="20dp"
app:cardBackgroundColor="#33ff0000"
app:cardCornerRadius="30dp">
<android.support.v7.widget.RecyclerView
android:id="@+id/rv_list_2"
android:layout_width="150dp"
android:layout_height="150dp" />
</android.support.v7.widget.CardView>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
CardView提供了相容版本,當5.0版本以上時,子view被圓角了, 那麼5.0版本以上時,支援嗎?經測試是不支援的,但是系統給它增加padding時子 view完全顯示在佈局裡面,不會超出圓角部分,算是適配的方法,這樣比上一種方法,更加合適了一點。
View#draw方法,提供了一個最基本的繪製機制,子類通常不需要重寫這個方法。我們可以通過檢視其原始碼,在View的draw裡面,它通常需要做以下幾件事情:
1,繪製自己的背景,如果有的話,因為背景始終都在最後面,所以要先畫。
2,如果需要的話,儲存canvas的layer來準備繪製漸變效果,比如說有alpha動畫等。
3,繪製View的內容,其實就是呼叫onDraw方法,讓子類可以繪製自己的內容。
4,繪製自己的child,具體怎麼繪製孩子,ViewGroup會去重寫相應的方法。基類的View只是把呼叫這繪製child的方法,當然這個方法在View裡面,應該是什麼都不做。
5,如果需要的話,畫漸變效果並還原儲存的canvas層。
6,繪製其他的元素,比如scrollbar等。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
通常,View裡面要做這些事情,而且順序不能改變。
注意第4點,繪製子view的方法,這樣的話,如果在繪製子view之前,要是給canvas設定圓角的path,是不是就可以呢。
/**
* 圓角的RelativeLayout
*
*/
public class RoundRectLayout extends RelativeLayout {
private Path mPath;
private int mRadius;
private int mWidth;
private int mHeight;
private int mLastRadius;
public static final int MODE_NONE = 0;
public static final int MODE_ALL = 1;
public static final int MODE_LEFT = 2;
public static final int MODE_TOP = 3;
public static final int MODE_RIGHT = 4;
public static final int MODE_BOTTOM = 5;
private int mRoundMode = MODE_ALL;
public RoundRectLayout(Context context) {
super(context);
init();
}
public RoundRectLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init(){
setBackgroundDrawable(new ColorDrawable(0x33ff0000));
mPath = new Path();
mPath.setFillType(Path.FillType.EVEN_ODD);
setCornerRadius(ViewUtil.dp2px(getContext(), 30));
}
/**
* 設定是否圓角裁邊
* @param roundMode
*/
public void setRoundMode(int roundMode){
mRoundMode = roundMode;
}
/**
* 設定圓角半徑
* @param radius
*/
public void setCornerRadius(int radius){
mRadius = radius;
}
private void checkPathChanged(){
if(getWidth() == mWidth && getHeight() == mHeight && mLastRadius == mRadius){
return;
}
mWidth = getWidth();
mHeight = getHeight();
mLastRadius = mRadius;
mPath.reset();
switch (mRoundMode){
case MODE_ALL:
mPath.addRoundRect(new RectF(0, 0, mWidth, mHeight), mRadius, mRadius, Path.Direction.CW);
break;
case MODE_LEFT:
mPath.addRoundRect(new RectF(0, 0, mWidth, mHeight),
new float[]{mRadius, mRadius, 0, 0, 0, 0, mRadius, mRadius},
Path.Direction.CW);
break;
case MODE_TOP:
mPath.addRoundRect(new RectF(0, 0, mWidth, mHeight),
new float[]{mRadius, mRadius, mRadius, mRadius, 0, 0, 0, 0},
Path.Direction.CW);
break;
case MODE_RIGHT:
mPath.addRoundRect(new RectF(0, 0, mWidth, mHeight),
new float[]{0, 0, mRadius, mRadius, mRadius, mRadius, 0, 0},
Path.Direction.CW);
break;
case MODE_BOTTOM:
mPath.addRoundRect(new RectF(0, 0, mWidth, mHeight),
new float[]{0, 0, 0, 0, mRadius, mRadius, mRadius, mRadius},
Path.Direction.CW);
break;
}
}
@Override
public void draw(Canvas canvas) {
if(mRoundMode != MODE_NONE){
int saveCount = canvas.save();
checkPathChanged();
canvas.clipPath(mPath);
super.draw(canvas);
canvas.restoreToCount(saveCount);
}else {
super.draw(canvas);
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
這裡,複寫draw方法,在super.draw方法之前,給當前canvas設定path,這個path設定為圓角的方形。
然後在這個view包裹在自 view外,
<round.llh.com.roundtotalview.RoundRectLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_margin="20dp">
<android.support.v7.widget.RecyclerView
android:id="@+id/rv_list_4"
android:layout_width="150dp"
android:layout_height="150dp" />
</round.llh.com.roundtotalview.RoundRectLayout>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
這樣經測試,5.0以上和以下版本效果都是可以的,當然消耗也是存在的,每次繪製之前,都要canvas.clipPath(mPath);,在複雜的view或者動畫中,有可能不流暢,所有請謹慎使用。
以上四種方法各有利弊,大家可以選擇自己合適的方式來實現圓角。
原文連結:https://blog.csdn.net/hesong1120/article/details/52005895