*本篇文章已授權微信公眾號 guolin_blog (郭霖)獨家發(fā)布 *
之前在UI中國上看到一個側滑效果堡牡,覺得還不錯,于是就想實現(xiàn)一下锈嫩。
UI效果是這樣的:http://www.ui.cn/detail/198520.html
我自己實現(xiàn)的效果是這樣的:
效果并沒有完全一致胁附,UI效果里當兩部分重合后有一種像水滴重合一樣的效果榴啸,我并不知道用代碼如何實現(xiàn)(如果大家知道請告訴我呜象。膳凝。。)恭陡,所以我這里只是簡單的做了一個慢慢出現(xiàn)的效果蹬音。
好了,那我們就來看看這個效果是怎么實現(xiàn)的休玩。
首先
這是一個自定義View著淆。
效果分為兩個部分,一個是背景的紅色拴疤,一個是白色的叉叉牧抽。
背景的紅色
當看到紅色的效果的時候,我就想到了貝塞爾曲線遥赚。貝塞爾曲線是個神奇的東西,幾乎所有神奇的曲線效果都可以用貝塞爾曲線來做阐肤。為了讓這篇文章保持簡潔凫佛,所以我就不介紹貝塞爾曲線了,如果有不了解的人孕惜,可以去這里看看愧薛。
到這里,我就假設你們都已經(jīng)知道怎么畫貝塞爾曲線啦衫画。
我想你們也猜到了毫炉,紅色效果其實就是用的三階貝塞爾曲線。
這個圖畫的就是紅色效果的示意圖(為了介紹所以將圖畫成了半圓削罩,實際效果里瞄勾,圓是扁扁的)。為了便于計算我將它設置為了一個正方形弥激,圖中的x2,x3,x5,x6都是中點进陡。我們用Path.cubicTo()方法將x1到x7這七個點連起來之后就可以得一個半圓形了。
我們整個效果微服,其實就是控制這幾個點而已趾疚。
背景紅色的運動過程
在這里,我會直接給出代碼來講解。
為了便于計算糙麦,我們先將控件的寬高設為相等辛孵,讓它變成一個正方形:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec,widthMeasureSpec);
}
然后就是繪制背景紅色了,其實這個紅色有上下兩個赡磅,但是兩個其實是一樣的魄缚,所以我就只介紹上半部分。
pathUp.reset();
pathUp.moveTo(0,0);
pathUp.cubicTo(x2,y26,0,y345,radius,y345);
pathUp.cubicTo(radius*2,y345,x6,y26,radius*2,0);
pathUp.lineTo(0,0);
canvas.drawPath(pathUp,paint);
這里的過程就是從x1點開始連接一直連接到x7仆邓,最后在連到x1械巡。
其中x2表示x2點的x坐標整葡,y26表示x2點和x6點的y坐標,其余類同(取名字真的好累)。
radius表示圓的半徑登刺,也就是正方形邊長的一半。
代碼里嗤朴,x3點和x5點的橫坐標被我設置為和x1,x7一樣剥懒,這樣可以讓圓扁一點。
我們需要變化的點匿乃,其實就是x2,x6,y26,y345這四個點而已桩皿。
y345,y26需要上下移動幢炸,來達到變小變大的效果泄隔。
至于x2,x6則是需要向外擴大,不然最后y345就算捅穿地表也不能把兩邊填滿宛徊。
現(xiàn)在我們知道了需要變化的點的軌跡佛嬉,那我們怎么控制它們呢?
我在View里寫了一個方法:
public void controllAnimation(int progress,float max)
這個方法接收兩個參數(shù)闸天,第一個是當前值暖呕,第二個是最大的值。通過 當前值/最大值 我們就可以獲取一個百分比的進度值苞氮。通過這個進度值我們就可以計算出當前點的位置:
public void controllAnimation(int progress,float max){
double fraction = progress/max;
//這里根據(jù)進度改變湾揽,慢慢的變化
y345 = (float) (radius*2*(fraction));
if(y345<radius){
x2 = 0;
x6 = radius*2-x2;
}else {
x2 = (float) (-radius*2*((fraction-0.5)/fraction));
x6 = radius*2-x2;
}
y26 = (float) (radius*fraction);
invalidate();
}
現(xiàn)在這個我用了一個seekBar,等到將其放進真的比如RecyclerView的側滑刪除時笼吟,只要將滑動距離作為progress參數(shù)傳進去库物,滑動最大值作為max傳進去就可以了。
白色叉叉
叉叉就簡單多了贷帮,圖上的每個點都是中點艳狐。
叉叉也是分上半部和下半部,我們這里就只講講上半部分皿桑,下半部分一樣的毫目。
//這里畫那個叉叉
//這是上半部分
pathCha.reset();
pathCha.moveTo((halfRadius*3)/2,radius);
pathCha.lineTo(halfRadius,chaY1);
pathCha.lineTo((halfRadius*3)/2,chaY2);
pathCha.lineTo(radius,chaY1);
pathCha.lineTo((radius*2)-((halfRadius*3)/2),chaY2);
pathCha.lineTo(halfRadius*3,chaY1);
pathCha.lineTo((radius*2)-((halfRadius*3)/2),radius);
pathCha.lineTo((halfRadius*3)/2,radius);
這里radius表示半徑蔬啡,halfRadius表示半徑的一半。
chaY1等于(radius*3)/4
chaY2等于 radius/2
chaY1表示x1,x3,x5點的y坐標镀虐,chaY2表示x2,x4點的y坐標箱蟆。
我們需要改變的就是chaY1和chaY2的值,來達到一種叉叉慢慢出現(xiàn)的感覺刮便。
代碼如下:
if(y345<radius){
//一些代碼
}else {
...
//慢慢的畫出叉
chaY1 = (float) (radius-(chaLength*2*((fraction-0.5)/fraction)));
chaY2 = (float) (radius-(halfRadius*2*((fraction-0.5)/fraction)));
}
我們的叉叉是在上下兩個紅色接觸在一起的時候才繪制的空猜,也就是進度為一半的時候。
這樣就把這個View說完了恨旱,View的代碼也不是很長辈毯,我就直接貼出來吧:
public class CeHuaView extends View {
Paint paint,paintCha;
Path pathUp,pathDown,pathCha,pathCha2;
int width;
float radius;
float halfRadius;
//這里取名字有點隨便,因為不知道怎么取搜贤,可以看我博客里的圖谆沃,應該就能知道意思了
//這里y表示上半部分,yy表示下半部分仪芒,x同理
float y345,yy345;
float y26,yy26;
float x2,x6;
float chaLength;
float chaY1,chaY2;
public CeHuaView(Context context) {
this(context,null);
}
public CeHuaView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs,0);
}
public CeHuaView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
pathUp = new Path();
pathDown = new Path();
pathCha = new Path();
pathCha2 = new Path();
paint = new Paint();
paint.setColor(Color.parseColor("#ff5777"));
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.FILL);
paintCha = new Paint();
paintCha.setColor(Color.parseColor("#ffffff"));
paintCha.setAntiAlias(true);
paintCha.setStyle(Paint.Style.FILL);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec,widthMeasureSpec);
width = MeasureSpec.getSize(widthMeasureSpec);
radius = width/2;
halfRadius = width/4;
y345 = radius;
yy345 = radius;
y26 = halfRadius;
yy26 = halfRadius*3;
x2 = 0;
x6 = radius*2;
chaLength = radius/4;
chaY1 = chaLength*3;
chaY2 = chaLength*2;
}
public void controllAnimation(int progress,float max){
double fraction = progress/max;
//這里根據(jù)進度改變唁影,慢慢的變化
y345 = (float) (radius*2*(fraction));
yy345 = radius*2-y345;
if(y345<radius){
x2 = 0;
x6 = radius*2-x2;
}else {
x2 = (float) (-radius*2*((fraction-0.5)/fraction));
x6 = radius*2-x2;
//慢慢的畫出叉
chaY1 = (float) (radius-(chaLength*2*((fraction-0.5)/fraction)));
chaY2 = (float) (radius-(halfRadius*2*((fraction-0.5)/fraction)));
}
y26 = (float) (radius*fraction);
yy26 = (float) ((radius*2)-(radius*fraction));
invalidate();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//這里畫粘稠的效果
//這是上半部分
pathUp.reset();
pathUp.moveTo(0,0);
pathUp.cubicTo(x2,y26,0,y345,radius,y345);
pathUp.cubicTo(radius*2,y345,x6,y26,radius*2,0);
pathUp.lineTo(0,0);
canvas.drawPath(pathUp,paint);
//這里畫粘稠的效果
//這是下半部分
pathDown.reset();
pathDown.moveTo(0,radius*2);
pathDown.cubicTo(x2,yy26,0,yy345,radius,yy345);
pathDown.cubicTo(radius*2,yy345,x6,yy26,radius*2,radius*2);
pathDown.lineTo(0,radius*2);
canvas.drawPath(pathDown,paint);
if(y345>radius){
//這里畫那個叉叉
//這是上半部分
pathCha.reset();
pathCha.moveTo((halfRadius*3)/2,radius);
pathCha.lineTo(halfRadius,chaY1);
pathCha.lineTo((halfRadius*3)/2,chaY2);
pathCha.lineTo(radius,chaY1);
pathCha.lineTo((radius*2)-((halfRadius*3)/2),chaY2);
pathCha.lineTo(halfRadius*3,chaY1);
pathCha.lineTo((radius*2)-((halfRadius*3)/2),radius);
pathCha.lineTo((halfRadius*3)/2,radius);
//這是下半部分
pathCha.lineTo((radius*2)-((halfRadius*3)/2),radius);
pathCha.lineTo(halfRadius*3,radius*2-chaY1);
pathCha.lineTo((radius*2)-((halfRadius*3)/2),radius*2-chaY2);
pathCha.lineTo(radius,radius*2-chaY1);
pathCha.lineTo((halfRadius*3)/2,radius*2-chaY2);
pathCha.lineTo(halfRadius,radius*2-chaY1);
canvas.drawPath(pathCha,paintCha);
}
}
}
在RecyclerView里應用
因為這篇文章主要也不是講RecyclerView的側滑實現(xiàn)的,所以這方面的知識大家可以去這里看看掂名。
在RecyclerView應用的代碼也參考自這里据沈。
好了,本篇文章結束了饺蔑。
還有很多不完善的地方锌介,也和UI中國的效果有出入,需要調(diào)整猾警。
才疏學淺孔祸,如有錯誤,歡迎大家批評指正肿嘲。
最后
本篇文章的代碼:CeHuaView
最后的最后
感謝我可愛的女朋友。