著名的貝塞爾曲線,確實(shí)是很美,很美。本文記錄對貝塞爾曲線的點(diǎn)滴認(rèn)識
貝塞爾曲線.gif
二次貝塞爾曲線,求最高點(diǎn),反向求控制點(diǎn)
二次貝塞爾曲線-反向求控制點(diǎn).gif
求 二次貝塞爾的 最高點(diǎn)
/** * 計算 二階貝塞爾曲線的坐標(biāo) * * @param t 曲線長度比例, 進(jìn)度比例 [0, 1] * @param startPointF 開始點(diǎn) * @param controlPointF 控制點(diǎn) * @param endPointF 結(jié)束點(diǎn) * @return */ public static PointF getBezierPointF(float t, PointF startPointF, PointF endPointF, PointF controlPointF) { PointF pointF = new PointF(0, 0); float tmp = 1 - t; pointF.x = tmp * tmp * startPointF.x + 2 * t * tmp * controlPointF.x + t * t * endPointF.x; pointF.y = tmp * tmp * startPointF.y + 2 * t * tmp * controlPointF.y + t * t * endPointF.y; return pointF; }
反向 求二次貝塞爾曲線 的控制點(diǎn)
/** * 根據(jù) 最高點(diǎn),獲取貝塞爾曲線的 控制點(diǎn) * * @param startPointF 開始點(diǎn) * @param endPointF 結(jié)束點(diǎn) * @param bezierPointF 最高點(diǎn) * @return */ public static PointF getControlPointF(PointF startPointF, PointF endPointF, PointF bezierPointF) { PointF controlPointF = new PointF(0, 0); float tmp = 0.5F; float t = 0.5F; controlPointF.x = (bezierPointF.x - tmp * tmp * startPointF.x - t * t * endPointF.x) / (2 * t * tmp); controlPointF.y = (bezierPointF.y - tmp * tmp * startPointF.y - t * t * endPointF.y) / (2 * t * tmp); return controlPointF; }
開始 仿 QQ“一鍵退朝”
貝塞爾.gif
代碼,來說,沒有什么好講的,網(wǎng)上的教程,也是比較多的,記錄一下,算法的實(shí)現(xiàn)過程吧。
先找到兩個圓的 外切點(diǎn)
Paste_Image.png
Paste_Image.png
sin(γ) = (R - r) / oP0; 因?yàn)?R - r 和 原點(diǎn) 到 P0的距離,都是已知條件,所以根據(jù)反正弦函數(shù),可以得出γ的大小;
因?yàn)?α + γ + 90 + β = 180;所以可以得出,β的大??; 再已知 r 和 β的大小,就可以得出 P1 的坐標(biāo),從而也能推理得出 P2, P3,P4的坐標(biāo);
找兩個控制點(diǎn) P5 和 P6
Paste_Image.png
所有的點(diǎn),都找好了,開始畫貝塞爾曲線
- 先將路徑移到P1
path.moveTo(stickTangent0PointF.x, stickTangent0PointF.y);
- 畫二次貝塞爾曲線,起點(diǎn)是P1,控制點(diǎn)是P5,結(jié)束點(diǎn)是P2
path.quadTo(control0PointF.x, control0PointF.y, dragTangent0PointF.x, dragTangent0PointF.y);
- P2到P4畫一條直線
path.lineTo(dragTangent1PointF.x, dragTangent1PointF.y);
- 畫二次貝塞爾曲線,起點(diǎn)是P4,控制點(diǎn)事P6,結(jié)束點(diǎn)是P3
path.quadTo(control1PointF.x, control1PointF.y, stickTangent1PointF.x, stickTangent1PointF.y);
此時,就算畫完了,看一下鏤空的效果
Paste_Image.png
先看最終的效果, 仿 QQ“一鍵退朝”,我該怎么做?
鼻涕蟲效果.gif
先看布局文件
<org.alex.viewbadge.WrapTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="32dp"
app:wv_backgroundColor="#FF0000"
app:wv_dismissBoomResId="@drawable/tips_bubble"
app:wv_shape="oval"
app:wv_text="9"
app:wv_textColor="#FFFFFF"
app:wv_textSize="10sp" />
UI上怎么統(tǒng)一?
先在布局上展示一個 包裹內(nèi)容的 文本控件, 在onTouch 的MotionEvent.ACTION_DOWN 事件,將WrapTextView隱藏掉,再把 DraggingView 添加到windowManager上,同時展示 出來,那么問題來了,WrapTextView 和 DraggingView 是兩個 控件,怎么能保證效果上,長得一樣呢?這時候,畫控件使用的是代理模式,用CanvasHelper去控制View的繪制工作。
兩個控件怎么同步狀態(tài)?
我們采用觀察者模式,也就是常說的接口回調(diào),用OnDraggingStatusListener關(guān)聯(lián)二者的狀態(tài)
聽首歌 ,放松一下 風(fēng)繼續(xù)吹 - 張國榮
源碼地址 參考文章
http://www.jianshu.com/p/2a3167a5a811 http://www.jianshu.com/p/dce9794ed07e http://www.jianshu.com/p/ec25be92c8fd http://www.jianshu.com/p/6e8c06df7386 http://www.jianshu.com/p/75db5961b496 http://www.jianshu.com/p/4a022f9bb121 http://www.jianshu.com/p/6d4944d83dc2 http://www.jianshu.com/p/c0d7ad796cee http://www.jianshu.com/p/3a57ecd949b6 http://www.jianshu.com/p/887b1ef3362d http://www.jianshu.com/p/55c721887568 http://www.jianshu.com/p/3cb3b5370ae0 http://www.jianshu.com/p/791d3a791ec2 http:///2015/03/30/Android-Animation-%E8%B4%9D%E5%A1%9E%E5%B0%94%E6%9B%B2%E7%BA%BF%E4%B9%8B%E7%BE%8E/ http://isux.tencent.com/qq-mobile-off-duty.html https://github.com/PoplarTang/DragGooView
|