很久很久沒有寫博客了,說來也有點慚愧。正好最近整理自己的項目工程目錄,看到一些值得分享的控件,準備在之後的幾篇博客中準備把它們陸續搬運上來。
這篇博客準備整理一下Android Material Design自帶的點擊水波紋擴散的效果。話不多說,開始正題。
水波紋效果分爲兩種:有界水波紋和無界水波紋。都通過系統自帶的動畫文件實現。
有界水波紋:
有界水波紋通過系統自帶的動畫文件 selectableItemBackground 實現只要將其設置爲控件的背景即可。簡單寫幾句代碼:
<Button
android:id="@+id/button"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_margin="15dp"
android:background="?android:attr/selectableItemBackground"
android:text="Button" />
效果如下:
無界水波紋:
無界水波紋通過動畫文件 selectableItemBackgroundBorderless 實現,用法和有界水波紋一樣,修改一下上面的代碼:
<Button
android:id="@+id/button"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_margin="15dp"
android:background="?android:attr/selectableItemBackgroundBorderless"
android:text="Button" />
效果:
可以看到,所謂的有界和無界的區別就在於,有界水波紋擴散不會超出控件自身的邊界,而無界水波紋擴散範圍是一個正方形區域,正方形的邊長取控件高寬的較大值。
當然這樣的效果還是太單調,有時我們需要自定義水波紋的顏色,方法也很簡單。
有界水波紋:
要自定義有界水波紋的顏色,只需要創建drawable文件,添加ripple節點,將節點的color屬性設置爲你想要的顏色,再在其下添加item節點,指定該item的id屬性爲mask即可。
比如說我們定義“button_red_mask”文件:
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#FF5151">
<item
android:id="@android:id/mask"
android:drawable="@color/colorPrimary" />
</ripple>
item節點中的drawable屬性另有用處,之後再講,但這裏並不影響水波紋的顏色,我這裏就隨便設了一個。之後再將這個文件設置爲控件的背景即可:
<Button
android:id="@+id/button"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_margin="15dp"
android:background="@drawable/button_red_mask"
android:text="Button" />
看看效果:
無界水波紋:
無界水波紋要自定義波紋顏色就更簡單了,連上述的item節點都不需要,只需要ripple節點指定其color屬性即可。
定義“button_red_mask “文件:
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#FF5151">
</ripple>
再將其設置爲控件的背景:
<Button
android:id="@+id/button"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_margin="15dp"
android:background="@drawable/button_red_unmask"
android:text="Button" />
效果:
除了自定義波紋顏色,你甚至可以自定義波紋的擴散邊界。做法也不復雜,就是我們之前提到的item節點中的drawable屬性,只需要將drawable屬性設置爲指定的圖片,就可以將該圖片作爲擴散邊界。來試一試。
定義“button_red_mask_icon“文件:
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#FF5151">
<item
android:id="@android:id/mask"
android:drawable="@drawable/heart" />
</ripple>
將其設置爲控件的背景:
<Button
android:id="@+id/button"
android:layout_width="350dp"
android:layout_height="350dp"
android:layout_gravity="center_horizontal"
android:background="@drawable/button_red_mask_icon"
android:text="Button" />
看看效果:
當然自定義邊界所指定的圖片,除了真實的圖片,自定義的drawble資源也是可以的。
比如說我們先定義一個圓角矩形資源“button_red_up”
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#ff5151" />
<corners android:radius="40dp" />
</shape>
再定義一個“button_red_mask_shape”文件,將item節點的drawable屬性設置爲上面的“button_red_up”:
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#FF5151">
<item
android:id="@android:id/mask"
android:drawable="@drawable/button_red_up" />
</ripple>
最後把它設置成控件的背景:
<Button
android:id="@+id/button"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_margin="15dp"
android:background="@drawable/button_red_mask_shape"
android:text="Button" />
效果如下:
當然,上面的所有做法,控件的不點擊的時候是不顯示形狀的。有時候我們需要控件的不點擊的時候就顯示一個指定的形狀,那又該怎麼做呢?其實也不難,只需要在上述的item節點下,再添加一個shape節點來指定形狀即可。
我們再定義一個“button_red_mask_shape_pro”文件:
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#20000000">
<item>
<shape>
<corners android:radius="40dp" />
<solid android:color="#FF5151" />
</shape>
</item>
</ripple>
這個文件指定了控件形狀爲圓角矩形,水波紋顏色爲半透明的黑色。再把這個文件設置爲控件的背景:
<Button
android:id="@+id/button"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_margin="15dp"
android:background="@drawable/button_red_mask_shape_pro"
android:text="Button" />
效果:
再進一步,如果還想給按鈕再加一個selector效果,即按鈕未按下時顯示一張圖,按下時顯示另一張圖,也是可以做到的。
先定義一個按鈕未按下時的資源“button_red_up”:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#ff5151" />
<corners android:radius="40dp" />
</shape>
再定義一個按鈕按下時的資源“button_red_down”:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#BA3F3F" />
<corners android:radius="40dp" />
</shape>
然後定義selector資源文件“button_red_mask_shape_selector”:
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#20000000">
<item>
<selector>
<item
android:state_pressed="true"
android:drawable="@drawable/button_red_down"/>
<item
android:state_pressed="false"
android:drawable="@drawable/button_red_up"/>
</selector>
</item>
</ripple>
其實就是在item節點下再添加一個selector節點,引用之前定義的兩個資源即可。最後把控件的背景設置爲該資源:
<Button
android:id="@+id/button"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_margin="15dp"
android:background="@drawable/button_red_mask_shape_selector"
android:text="Button" />
來看看效果:
好了,以上就是Andorid的Material Design中自帶的水波紋擴散效果的所有內容了。
===========================================================
其實之前自己順手寫了一個點擊水波紋擴散效果的控件,雖然從來沒有用過,這裏也順便拿出來分享一下,沒準以後就用上了呢。
話不多說,先看效果:
實現的效果是點擊時生成一個隨手指移動的小圓圈,鬆開時小圓圈呈現水波紋擴散效果,之前在前端上經常看到這樣的設計。
所有代碼都被封裝在一個視圖類裏面,複製即可用。上源碼:
按鈕類 DiffusionButton.java
public class DiffusionButton extends AppCompatButton {
private Context context;
private Paint paint;
private Path path;
private RectF roundRect;
private int width;
private int height;
private int touchX;
private int touchY;
private int maxRadius;
private int currentRadius;
private int invalidateInterval = 10;
private boolean isPushButton;
private boolean isClickFinish;
private boolean isInit;
/**
* 可設置參數
*/
// 擴散速度
private int speed;
// 擴散顏色
private int diffusionColor;
// 控件圓角半徑
private int radius;
// 控件左上角橫向半徑
private int leftTopRadiusX;
// 控件左上角縱向半徑
private int leftTopRadiusY;
// 控件右上角橫向半徑
private int rightTopRadiusX;
// 控件右上角縱向半徑
private int rightTopRadiusY;
// 控件左下角橫向半徑
private int leftBottomRadiusX;
// 控件左下角縱向半徑
private int leftBottomRadiusY;
// 控件右下角橫向半徑
private int rightBottomRadiusX;
// 控件右下角縱向半徑
private int rightBottomRadiusY;
// 按下時的圓圈半徑
private int touchRadius;
public DiffusionButton(Context context) {
super(context, null);
}
public DiffusionButton(Context context, AttributeSet attrs) {
this(context, attrs, R.attr.buttonStyle);
}
public DiffusionButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.DiffusionButton);
speed = array.getInt(R.styleable.DiffusionButton_speed, 25);
diffusionColor = array.getColor(R.styleable.DiffusionButton_diffusionColor, Color.parseColor("#30000000"));
radius = array.getDimensionPixelSize(R.styleable.DiffusionButton_radius, 0);
leftTopRadiusX = array.getDimensionPixelSize(R.styleable.DiffusionButton_leftTopRadiusX, radius);
leftTopRadiusY = array.getDimensionPixelSize(R.styleable.DiffusionButton_leftTopRadiusY, radius);
leftBottomRadiusX = array.getDimensionPixelSize(R.styleable.DiffusionButton_leftBottomRadiusX, radius);
leftBottomRadiusY = array.getDimensionPixelSize(R.styleable.DiffusionButton_leftBottomRadiusY, radius);
rightTopRadiusX = array.getDimensionPixelSize(R.styleable.DiffusionButton_rightTopRadiusX, radius);
rightTopRadiusY = array.getDimensionPixelSize(R.styleable.DiffusionButton_rightTopRadiusY, radius);
rightBottomRadiusX = array.getDimensionPixelSize(R.styleable.DiffusionButton_rightBottomRadiusX, radius);
rightBottomRadiusY = array.getDimensionPixelSize(R.styleable.DiffusionButton_rightBottomRadiusY, radius);
touchRadius = array.getDimensionPixelSize(R.styleable.DiffusionButton_touchRadius, dp2px(20));
array.recycle();
init(context);
}
/**
* 初始化方法
*
* @param context
*/
private void init(Context context) {
this.context = context;
paint = new Paint();
paint.setColor(diffusionColor);
path = new Path();
}
/**
* 構造剪裁路徑方法
*/
private void buildPath() {
if (path == null) {
return;
}
path.reset();
path.addRoundRect(roundRect, new float[]{
leftTopRadiusX, leftTopRadiusY,
rightTopRadiusX, rightTopRadiusY,
rightBottomRadiusX, rightBottomRadiusY,
leftBottomRadiusX, leftBottomRadiusY,
}, Path.Direction.CCW);
}
/**
* 擴散動畫完成後重置方法
*/
private void resetData() {
isPushButton = false;
isClickFinish = false;
currentRadius = touchRadius;
invalidate();
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
width = getMeasuredWidth();
height = getMeasuredHeight();
roundRect = new RectF(0, 0, width, height);
buildPath();
isInit = true;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (!isPushButton && !isClickFinish) {
return;
}
// 剪裁顯示區域
canvas.clipPath(path);
if (isClickFinish) {
// 繪製擴散圓
canvas.drawCircle(touchX, touchY, currentRadius, paint);
if (currentRadius < maxRadius) {
currentRadius += speed;
postInvalidateDelayed(invalidateInterval);
} else {
resetData();
}
}
if (isPushButton) {
// 繪製點擊圓
canvas.drawCircle(touchX, touchY, touchRadius, paint);
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touchX = (int) event.getX();
touchY = (int) event.getY();
isPushButton = true;
invalidate();
break;
case MotionEvent.ACTION_MOVE:
touchX = (int) event.getX();
touchY = (int) event.getY();
invalidate();
break;
case MotionEvent.ACTION_UP:
if (touchX > 0 && touchY > 0 && touchX < width && touchY < height) {
isPushButton = false;
isClickFinish = true;
// 計算最大擴散半徑
maxRadius = (int) Math.max(Math.max(getDistance(touchX, touchY, 0, 0), getDistance(touchX, touchY, 0, height)),
Math.max(getDistance(touchX, touchY, width, 0), getDistance(touchX, touchY, width, height)));
currentRadius = touchRadius;
postInvalidateDelayed(invalidateInterval);
} else {
resetData();
}
break;
}
return super.onTouchEvent(event);
}
private double getDistance(int x1, int y1, int x2, int y2) {
return Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2));
}
/**
* 設置擴散速度
*
* @param speed
*/
public void setSpeed(int speed) {
this.speed = speed;
}
/**
* 設置擴散顏色
*
* @param diffusionColor
*/
public void setDiffusionColor(int diffusionColor) {
this.diffusionColor = diffusionColor;
if (paint != null) {
paint.setColor(diffusionColor);
}
}
/**
* 設置控件圓角半徑
*
* @param radius 半徑,單位dp
*/
public void setRadius(int radius) {
if (radius >= 0) {
this.radius = dp2px(radius);
leftTopRadiusX = radius;
leftTopRadiusY = radius;
rightTopRadiusX = radius;
rightTopRadiusY = radius;
leftBottomRadiusX = radius;
leftBottomRadiusY = radius;
rightBottomRadiusX = radius;
rightBottomRadiusY = radius;
if (isInit) {
buildPath();
}
}
}
/**
* 設置控件圓角半徑
* <p>
* 參數爲四個數組,分別對應控件左上角橫縱向半徑、右上角橫縱向半徑、左下角橫縱向半徑、右下角橫縱向半徑
*
* @param leftTopRadius 半徑,單位dp,下同
* @param rightTopRadius
* @param leftBottomRadius
* @param rightBottomRadius
*/
public void setRadius(int[] leftTopRadius, int[] rightTopRadius, int[] leftBottomRadius, int[] rightBottomRadius) {
leftTopRadiusX = dp2px(leftTopRadius[0]);
leftTopRadiusY = dp2px(leftTopRadius[1]);
rightTopRadiusX = dp2px(rightTopRadius[0]);
rightTopRadiusY = dp2px(rightTopRadius[1]);
leftBottomRadiusX = dp2px(leftBottomRadius[0]);
leftBottomRadiusY = dp2px(leftBottomRadius[1]);
rightBottomRadiusX = dp2px(rightBottomRadius[0]);
rightBottomRadiusY = dp2px(rightBottomRadius[1]);
if (isInit) {
buildPath();
}
}
/**
* 設置按下時的圓圈半徑
*
* @param touchRadius 半徑,單位dp
*/
public void setTouchRadius(int touchRadius) {
this.touchRadius = dp2px(touchRadius);
}
private int dp2px(int dpVal) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpVal, getResources().getDisplayMetrics());
}
}
佈局類 DiffusionLayout.java
public class DiffusionLayout extends LinearLayout {
private Context context;
private Paint paint;
private Path path;
private RectF roundRect;
private int width;
private int height;
private int touchX;
private int touchY;
private int maxRadius;
private int currentRadius;
private int invalidateInterval = 10;
private boolean isPushButton;
private boolean isClickFinish;
private boolean isInit;
/**
* 可設置參數
*/
// 擴散速度
private int speed;
// 擴散顏色
private int diffusionColor;
// 控件圓角半徑
private int radius;
// 控件左上角橫向半徑
private int leftTopRadiusX;
// 控件左上角縱向半徑
private int leftTopRadiusY;
// 控件右上角橫向半徑
private int rightTopRadiusX;
// 控件右上角縱向半徑
private int rightTopRadiusY;
// 控件左下角橫向半徑
private int leftBottomRadiusX;
// 控件左下角縱向半徑
private int leftBottomRadiusY;
// 控件右下角橫向半徑
private int rightBottomRadiusX;
// 控件右下角縱向半徑
private int rightBottomRadiusY;
// 按下時的圓圈半徑
private int touchRadius;
public DiffusionLayout(Context context) {
this(context, null);
}
public DiffusionLayout(Context context, AttributeSet attrs) {
this(context, attrs, -1);
}
public DiffusionLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.DiffusionLayout);
speed = array.getInt(R.styleable.DiffusionButton_speed, 25);
diffusionColor = array.getColor(R.styleable.DiffusionButton_diffusionColor, Color.parseColor("#30000000"));
radius = array.getDimensionPixelSize(R.styleable.DiffusionButton_radius, 0);
leftTopRadiusX = array.getDimensionPixelSize(R.styleable.DiffusionButton_leftTopRadiusX, radius);
leftTopRadiusY = array.getDimensionPixelSize(R.styleable.DiffusionButton_leftTopRadiusY, radius);
leftBottomRadiusX = array.getDimensionPixelSize(R.styleable.DiffusionButton_leftBottomRadiusX, radius);
leftBottomRadiusY = array.getDimensionPixelSize(R.styleable.DiffusionButton_leftBottomRadiusY, radius);
rightTopRadiusX = array.getDimensionPixelSize(R.styleable.DiffusionButton_rightTopRadiusX, radius);
rightTopRadiusY = array.getDimensionPixelSize(R.styleable.DiffusionButton_rightTopRadiusY, radius);
rightBottomRadiusX = array.getDimensionPixelSize(R.styleable.DiffusionButton_rightBottomRadiusX, radius);
rightBottomRadiusY = array.getDimensionPixelSize(R.styleable.DiffusionButton_rightBottomRadiusY, radius);
touchRadius = array.getDimensionPixelSize(R.styleable.DiffusionButton_touchRadius, dp2px(20));
array.recycle();
init(context);
}
/**
* 初始化方法
*
* @param context
*/
private void init(Context context) {
this.context = context;
paint = new Paint();
paint.setColor(diffusionColor);
path = new Path();
setWillNotDraw(false);
setClickable(true);
}
/**
* 構造剪裁路徑方法
*/
private void buildPath() {
if (path == null) {
return;
}
path.reset();
path.addRoundRect(roundRect, new float[]{
leftTopRadiusX, leftTopRadiusY,
rightTopRadiusX, rightTopRadiusY,
rightBottomRadiusX, rightBottomRadiusY,
leftBottomRadiusX, leftBottomRadiusY,
}, Path.Direction.CCW);
}
/**
* 擴散動畫完成後重置方法
*/
private void resetData() {
isPushButton = false;
isClickFinish = false;
currentRadius = touchRadius;
invalidate();
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
width = getMeasuredWidth();
height = getMeasuredHeight();
roundRect = new RectF(0, 0, width, height);
buildPath();
isInit = true;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (!isPushButton && !isClickFinish) {
return;
}
// 剪裁顯示區域
canvas.clipPath(path);
if (isClickFinish) {
// 繪製擴散圓
canvas.drawCircle(touchX, touchY, currentRadius, paint);
if (currentRadius < maxRadius) {
currentRadius += speed;
postInvalidateDelayed(invalidateInterval);
} else {
resetData();
}
}
if (isPushButton) {
// 繪製點擊圓
canvas.drawCircle(touchX, touchY, touchRadius, paint);
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touchX = (int) event.getX();
touchY = (int) event.getY();
isPushButton = true;
invalidate();
break;
case MotionEvent.ACTION_MOVE:
touchX = (int) event.getX();
touchY = (int) event.getY();
invalidate();
break;
case MotionEvent.ACTION_UP:
if (touchX > 0 && touchY > 0 && touchX < width && touchY < height) {
isPushButton = false;
isClickFinish = true;
// 計算最大擴散半徑
maxRadius = (int) Math.max(Math.max(getDistance(touchX, touchY, 0, 0), getDistance(touchX, touchY, 0, height)),
Math.max(getDistance(touchX, touchY, width, 0), getDistance(touchX, touchY, width, height)));
currentRadius = touchRadius;
postInvalidateDelayed(invalidateInterval);
} else {
resetData();
}
break;
}
return super.onTouchEvent(event);
}
private double getDistance(int x1, int y1, int x2, int y2) {
return Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2));
}
/**
* 設置擴散速度
*
* @param speed
*/
public void setSpeed(int speed) {
this.speed = speed;
}
/**
* 設置擴散顏色
*
* @param diffusionColor
*/
public void setDiffusionColor(int diffusionColor) {
this.diffusionColor = diffusionColor;
if (paint != null) {
paint.setColor(diffusionColor);
}
}
/**
* 設置控件圓角半徑
*
* @param radius 半徑,單位dp
*/
public void setRadius(int radius) {
if (radius >= 0) {
this.radius = dp2px(radius);
leftTopRadiusX = radius;
leftTopRadiusY = radius;
rightTopRadiusX = radius;
rightTopRadiusY = radius;
leftBottomRadiusX = radius;
leftBottomRadiusY = radius;
rightBottomRadiusX = radius;
rightBottomRadiusY = radius;
if (isInit) {
buildPath();
}
}
}
/**
* 設置控件圓角半徑
* <p>
* 參數爲四個數組,分別對應控件左上角橫縱向半徑、右上角橫縱向半徑、左下角橫縱向半徑、右下角橫縱向半徑
*
* @param leftTopRadius 半徑,單位dp,下同
* @param rightTopRadius
* @param leftBottomRadius
* @param rightBottomRadius
*/
public void setRadius(int[] leftTopRadius, int[] rightTopRadius, int[] leftBottomRadius, int[] rightBottomRadius) {
leftTopRadiusX = dp2px(leftTopRadius[0]);
leftTopRadiusY = dp2px(leftTopRadius[1]);
rightTopRadiusX = dp2px(rightTopRadius[0]);
rightTopRadiusY = dp2px(rightTopRadius[1]);
leftBottomRadiusX = dp2px(leftBottomRadius[0]);
leftBottomRadiusY = dp2px(leftBottomRadius[1]);
rightBottomRadiusX = dp2px(rightBottomRadius[0]);
rightBottomRadiusY = dp2px(rightBottomRadius[1]);
if (isInit) {
buildPath();
}
}
/**
* 設置按下時的圓圈半徑
*
* @param touchRadius 半徑,單位dp
*/
public void setTouchRadius(int touchRadius) {
this.touchRadius = dp2px(touchRadius);
}
private int dp2px(int dpVal) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpVal, getResources().getDisplayMetrics());
}
}
控件有兩個,DiffusionButton和DiffusionLayout,分別應對點擊按鈕和點擊佈局的使用場景。DiffusionButton繼承自Button,DiffusionLayout繼承自LinearLayout,像使用普通的Button和Layout來使用它們就可以了。
像下面這樣:
<com.min.diffusionbutton.view.DiffusionButton
android:id="@+id/button"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_margin="15dp"
android:background="@drawable/button_red_up"
android:text="Button"
android:textColor="#ffffff"
android:textSize="16dp"
app:radius="25dp" />
<com.min.diffusionbutton.view.DiffusionLayout
android:id="@+id/layout"
android:layout_width="350dp"
android:layout_height="350dp"
android:layout_margin="15dp"
android:background="@drawable/button_red_up"
app:radius="40dp"
app:touchRadius="40dp" />
運行一下就能看到開頭的效果了。
當然控件還支持一些自定義屬性設置,各個屬性的意義在源碼註釋裏已經寫的很清楚了,這裏不再贅述。
最後附上源碼地址:https://download.csdn.net/download/Sure_Min/12565978
這次的內容就到這裏,我們下次再見。