1. 程式人生 > >Android之實現妙趣橫生的粘連佈局

Android之實現妙趣橫生的粘連佈局

1概述

在手機QQ中,有一個功能叫“一鍵下班”,無論介面有多少資訊,只要你不想看,就可以手指一滑,將他們全部消滅。據說這個功能專為紅點恐懼症、資訊閱讀強迫症以及處女座暖心打造。這個功能已經上線許久,除了設計本身比較貼心外,其呈現效果也十分驚豔:



這個功能深受廣大使用者喜愛,那麼這樣一個場景到底是怎樣的實現的呢?面對各位開發哥哥的疑問,小編決定玩個大的,既然要寫,不如就寫一個拓展性強大一點的、不僅僅只適用於“一鍵下班”場景的吧,乾脆叫它粘連佈局 —— AdherentLayout。

2AdherentLayout

AdherentLayout是一個適用於粘連場景的的開源元件,它有以下特性:

1、除了可實現類似手Q“一鍵下班”場景,還可以實現其他你能想到的其他場景。

2、支援設定粘連長度、粘連頭部大小、粘連顏色、是否可以扯斷的設定。

3、支援使用者自定義粘連尾部的檢視定製。

4、支援扯斷時候的監聽事件。

3使用方法

<AdherentLayout>

<!-- 在這裡可以新增使用者的檢視(可選) -->  

< />

</AdherentLayout>

4介面說明

setColor(int color)

設定粘連顏色

setDismissedEnable(boolean isDismissed)

設定是否可以扯斷

setMaxAdherentLength(int maxAdherentLength)

設定粘連的最大長度

setMinHeaderCircleRadius(int minHeaderCircleRadius)

設定粘連頭部圓的最小半徑

setOnAdherentListener(OnAdherentListener onAdherentListener)

設定粘連事件的監聽器

5核心技術

要實現粘連效果,最重要的是掌握貝塞爾曲線的繪製。

6貝塞爾曲線

通俗的講,貝塞爾曲線就是用來精確畫出曲線的,通過若干個控制點來控制曲線的形狀與繪製。因為Android本身自帶支援二階、三階的貝塞爾曲線繪製的API,所以下面就只引出二階、三階的動態圖好了,具體的知識點可移步貝塞爾曲線初探。

二階:


三階:


從上圖可知,

二階是隻有一個控制點,對應quadTo(float x1, float y1, float x2, float y2),其中(x1,y1)是控制點,(x2,y2)是結束點。

三階有兩個控制點,對應cubicTo(float x1, float y1, float x2, float y2, float x3, float y3) ,其中(x1,y1)是第一控制點,(x2,y2)是第二控制點,(x3,y3)是結束點。

7具體實現


借用ISUX的一張圖,該粘連佈局的具體流程分以下兩種情況:

1、未超出粘連範圍:邊拖拽邊繪製粘連頭部圓、粘連尾部圓和粘連體。其中頭部圓和尾部圓都是用drawCircle進行繪製,粘連體通過p1、p2、p3、p4、控制點採用quadTo繪製兩條二階貝塞爾曲線並分別連線p1p3、p2p4閉合起來,取兩圓心距離的中點為控制點,通過拖拽過程中兩圓心的距離之比來控制頭部圓的放大縮小即可。鬆開手勢,開啟回彈動畫。

2、超出粘連範圍:只繪製粘連尾部圓即可。鬆開手勢,繪製結束。

其中,繪製粘連體的核心程式碼如下:

private void drawBezier(Canvas canvas) {

/* 求三角函式 */

float atan = (float) Math.atan((mFooterCircle.y - mHeaderCircle.y) / (mFooterCircle.x - mHeaderCircle.x));

float sin = (float) Math.sin(atan);

float cos = (float) Math.cos(atan);

/* 四個點 */

float headerX1 = mHeaderCircle.x - mCurrentRadius * sin;

float headerY1 = mHeaderCircle.y + mCurrentRadius * cos;

float headerX2 = mHeaderCircle.x + mCurrentRadius * sin;

float headerY2 = mHeaderCircle.y - mCurrentRadius * cos;

float footerX1 = mFooterCircle.x - mFooterCircle.radius * sin;

float footerY1 = mFooterCircle.y + mFooterCircle.radius * cos;

float footerX2 = mFooterCircle.x + mFooterCircle.radius * sin;

float footerY2 = mFooterCircle.y - mFooterCircle.radius * cos;

/* 控制點 */

float anchorX = ( mHeaderCircle.x + mFooterCircle.x ) / 2;

float anchorY = ( mHeaderCircle.y + mFooterCircle.y ) / 2;

/* 畫貝塞爾曲線 */

mPath.reset();

mPath.moveTo(headerX1, headerY1);

mPath.quadTo(anchorX, anchorY, footerX1, footerY1);

mPath.lineTo(footerX2, footerY2);

mPath.quadTo(anchorX, anchorY, headerX2, headerY2);

mPath.lineTo(headerX1, headerY1);

canvas.drawPath(mPath, mPaint);

}

8執行示例


9結語

聽說這個功能的效果實現,經過了開發與產品多次腦暴與打磨。之所以受使用者喜愛,除了實用外,更重要的是實現效果讓使用者覺得更有趣,更靈動,也更軟性。而且這個效果其實可以適用於多種場景。

騰訊Bugly 最專業的質量跟蹤平臺

精神哥、小蘿莉,為您定期分享應用崩潰解決方案