最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Android仿知乎客戶端關(guān)注和取消關(guān)注的按鈕點擊特效實現(xiàn)思路詳解

 更新時間:2016年09月21日 09:46:16   作者:軒轅223  
這篇文章主要介紹了Android仿知乎客戶端關(guān)注和取消關(guān)注的按鈕點擊特效實現(xiàn)思路詳解的相關(guān)資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下

先說明一下,項目代碼已上傳至github,不想看長篇大論的也可以先去下代碼,對照代碼,哪里不懂點哪里。
代碼在這https://github.com/zgzczzw/ZHFollowButton

前幾天發(fā)現(xiàn)知乎關(guān)注的點擊效果確實贊,查了一下實現(xiàn)方式,剛好看到這個問題,花了一天時間終于把這個效果實現(xiàn)了,現(xiàn)在來回答一下,很不幸,樓上各位的答案都不全對,且聽我一一道來。

首先,我先詳細(xì)觀察了一些知乎的效果,其中有一個很神奇的地方,如圖:






注意看第二張圖,這個圓形在擴散的時候,圓形底下的字還在,而且新的字也在圓形上,就這個效果實現(xiàn)起來最難。

首先看一下樓上各位的回答,歸納來說,一共有2種實現(xiàn)方式,ripple效果和用paint在canvas上手動畫圓

ripple:

ripple即波紋效果,是android API 21以后引入的一種material design的元素,是觸摸反饋的一種,也就是說點擊的時候會出現(xiàn)水波擴散的樣式,demo(見最后)中第一個按鈕就是用了ripple效果。

實現(xiàn)方式很簡單,實現(xiàn)一個這樣的drawable

第一個color是波紋顏色,item里面指定background正常的顏色,可以是一個shape,也可以是一個drawable,還可以是一個selector。

設(shè)置為按鈕的background即可

如果整個程序的theme用了meterial,那基本所有的帶點擊效果的控件,比如button都自帶這個波紋效果。不過需要注意的是這一套API是21以后才提供的,所以需要做兼容處理。

效果如下:




從圖中可以看出即使我設(shè)置了波紋為紅色(#FF0000),點擊后的效果也是淡紅色,我猜測因為是水波紋效果,為了不影響按鈕本身展示的內(nèi)容,android系統(tǒng)自動做了透明度的處理,另外從圖中也可以明顯的看出,水波紋和顯示的內(nèi)容是上下兩層的,互不影響,水波紋是在background層面上。這個效果做普通的點擊反饋還不錯,但絕對實現(xiàn)不出知乎這種用波紋刷新出內(nèi)容的效果。所以很容易能看出知乎的點擊效果不是用ripple做出來的。

Paint在canvas上畫圓

@chaossss 所說的用 paint在點擊的地方畫圓形,然后讓畫的圓形半徑慢慢變大,實現(xiàn)出擴散出去的樣式,我實現(xiàn)了一下,代碼如下:

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (mShouldDoAnimation) {
mMaxRadius = getMeasuredWidth() + 50;
if (mRevealRadius > mMinBetweenWidthAndHeight / 2)
mRevealRadius += mRevealRadiusGap * 4;
else
mRevealRadius += mRevealRadiusGap;//半徑變大
Paint mPaint = new Paint();
if (!mIsPressed) {
mPaint.setColor(Color.WHITE);
} else {
mPaint.setColor(Color.RED);
}//設(shè)置畫筆顏色
mPaint.setStyle(Paint.Style.FILL);
canvas.drawCircle(mCenterX, mCenterY, mRevealRadius, mPaint);

if (mRevealRadius <= mMaxRadius) {
//一定時間后再刷新
postInvalidateDelayed(INVALIDATE_DURATION);
} else {
if (mIsPressed) {
setTextColor(Color.WHITE);
this.setBackgroundColor(Color.RED);
} else {
setTextColor(Color.BLACK);
this.setBackgroundColor(Color.WHITE);
}
mShouldDoAnimation = false;
invalidate();
}
}
}

效果如圖:







本來覺得差不多就是這樣,但是跟知乎的效果比較一下,還是能發(fā)現(xiàn)差別的。用paint畫圓能實現(xiàn)的是在點擊的地方畫一個圓,然后半徑慢慢變大慢慢擴散。但是問題在于,畫的這個圓會蓋住顯示的內(nèi)容,而且畫的圓上也不能顯示內(nèi)容。我試過用drawText,也實現(xiàn)不了字和圓一起的效果,解決方法只有,畫的過程中改背景色和上面文字。

然后,畫完圓之后把圓擦掉,把下面的背景色和文字顯示出來。

這樣就會出現(xiàn)一次文字閃爍的問題,首先文字會消失掉,然后畫完圓之后才顯示出來。因為圓在擴散的時候是看不到文字的,只有等圓消失了,文字才能顯示出來。而知乎的效果是文字和圓一起刷出來,而且底下的文字還在,中間也沒有文字閃爍的問題,整個過程行云流水,看起來很順暢,好像用圓形揭開了幕布一樣。

綜上所述,樓上所有的答案都是答主們看到這個效果后第一反應(yīng)的實現(xiàn),其實如果不是我自己實現(xiàn)了一下,真的以為第二種方法就是知乎采用的,但是目前看來,很遺憾,知乎采用了一種更好的方式來實現(xiàn)這個效果。

那怎么辦呢,我也沒什么思路,怎么才能在畫圓的時候把字也畫在圓上,然后圓下面的背景也還有呢。沒什么思路,看看知乎的代碼吧,反編譯。

反編譯的過程我簡單說一下:

到知乎官網(wǎng)下載最新的知乎apk

用apktool反編譯apk,得到資源文件

在資源文件中搜索follow,這里一開始我搜的是ripple,因為我覺得這個效果總歸應(yīng)該和ripple有關(guān),沒結(jié)果,于是搜了follow,沒想到還真搜出來了。

RevealFollowButton這明顯就是我們要的波紋展開的控件,這就好說了,下一步就是去代碼里找到這個控件了。這里要記一下,這個控件的位置com.zhihu.android.app.ui.widget.RevealFollowButton。

反編譯代碼

將apk改名成rar,打開,可以找到里面的class文件

知乎用了multidex,所以會有兩個class文件,都拖出來放在dex2jar里反編譯一下,就能生成兩個jar包了,把jar包放在GUI里看一下,就能看到代碼了,雖然代碼被混淆過,但是基本邏輯還是能看出來的。

然后根據(jù)前面xml里的路徑找到RevelFollowButton的位置,打開代碼看就可以了。

這是類的繼承關(guān)系,RevealFollowButton繼承自RevealFrameLayout,然后繼承自ZHFrameLayout,這個ZHFrameLayout的父類就是FrameLayout了,從名字我們能看出,RevelFollowButton和RevealFrameLayout就是這個效果實現(xiàn)的兩個類了。



看到這個效果的實現(xiàn)是基于Framelayout,我就知道我們之前討論的方法其實都走錯了方向,如果告訴你用framelayout來實現(xiàn)這個效果,你會怎么做?

我的想法是加入兩個TextView到這個layout里,然后一個Visible一個gone,如此切換,后來看過代碼后,也證明我的這個想法是對的。

看,這里有兩個TextView。如此的話,其實切換TextView是很容易實現(xiàn)的,問題是怎么實現(xiàn)波紋切換的效果,那第一件事就是看onDraw函數(shù)了,對于GroupView來說是drawChild方法。

RevealFollowButton的drawChild方法沒什么內(nèi)容,基本是調(diào)用了父類,那么我們來看RevealFrameLayout的drawChild方法。

這里有兩部分邏輯,如果滿足一個條件,就做第一部分,一開始我也不知道這個條件是什么,混淆后的代碼能看懂大邏輯,像這種小邏輯只能走一步看一步了。所以假設(shè)這個條件永遠(yuǎn)false吧,看第二部分,看到這里瞬間明白了,原來是采用切割畫布的方式,把畫布切成一個圓的,就能做到顯示的內(nèi)容也在圓上,而不是內(nèi)容被覆蓋在圓下面了。然后同理,把這個圓形區(qū)域不斷擴大,然后不斷刷新,就是實現(xiàn)波形刷出內(nèi)容的效果了。代碼如下吧

protected boolean drawChild(Canvas canvas, View paramView, long paramLong) {
int i = canvas.save();
mPath.reset();
//mCenterX mCenterY是點擊的位置,在onTouchEvent里設(shè)置
//mRevealRadius是圓的半徑,會漸漸變大
mPath.addCircle(mCenterX, mCenterY, mRevealRadius, Path.Direction.CW);
canvas.clipPath(this.mPath);
boolean bool2 = super.drawChild(canvas, paramView, paramLong);
canvas.restoreToCount(i);
return bool2;
}

按照上面說的,肯定還有一個類似于定時器的東西,能不斷改變圓形的半徑,然后刷新,其實這個在代碼里找找很容易就找到了。RevealFrameLayout里除了這個drawChild,沒有別的代碼了。所以我們來看RevealFollowButton。

RevealFollowButton里面跟定時器有關(guān)的就是這句了

一個Animator對象,其實這句代碼我是沒看懂的,但邏輯很簡單,設(shè)置一個Animator,定時500ms,在這個過程中修改圓形半徑,然后刷新。

Math.hypot(getWidth(), getHeight()))

其中這個方法是根據(jù)勾股定理獲取三角形的斜邊長度,想想我們所要繪制的圓形半徑最長是多少,沒錯,就是TextView的對角線長度。所以,整個邏輯就很簡單了。

我搞了下代碼,就這樣吧

整個方法的代碼如下吧,還包括控制FollowTv和unFollowTv哪個顯示

protected void setFollowed(boolean isFollowed, boolean needAnimate) {
mIsFollowed = isFollowed;
if (isFollowed) {
mUnFollowTv.setVisibility(View.VISIBLE);
mFollowTv.setVisibility(View.VISIBLE);
mFollowTv.bringToFront();
} else {
mUnFollowTv.setVisibility(View.VISIBLE);
mFollowTv.setVisibility(View.VISIBLE);
mUnFollowTv.bringToFront();
}
if (needAnimate) {
ValueAnimator animator = ObjectAnimator.ofFloat(mFollowTv, "empty", 0.0F, (float) Math.hypot(getMeasuredWidth(), getMeasuredHeight()));
animator.setDuration(500L);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mRevealRadius = (Float) animation.getAnimatedValue();
invalidate();
}
});
animator.start();
}
}

根據(jù)當(dāng)前狀態(tài)把Follow的Textview或UnFollow的TextView顯示出來,然后設(shè)置一個定時器不斷擴大所要繪制圓的半徑,根據(jù)這個半徑裁剪畫布成一個漸漸變大的圓形,然后內(nèi)容就漸漸顯示出來了。

這個效果實現(xiàn)出來之后,試著運行一下,還不錯,但是總覺得有地方不對,于是細(xì)細(xì)觀察,終于發(fā)現(xiàn)了,知乎的那個效果在刷新的時候,底下的背景不是白色的,還是之前的狀態(tài),比如要變成關(guān)注的時候,背景中的未關(guān)注還是在的,而我們實現(xiàn)的這個,刷新的時候背景是白色的。

這是知乎的

這是我的

所以還是沒有知乎那么行云流水,所以我們是少了什么嗎。這時候想起來了,之前在RevealFrameLayout的drawChild里有一個判斷條件,當(dāng)時我們不知道它的邏輯是干什么的,現(xiàn)在看來。那部分邏輯就是處理這個的,畫子控件的時候,要畫兩個,F(xiàn)ollowTextView和UnFollowTextView,要隨圓形刷出的控件我們采用裁剪畫布的方式慢慢畫出。那作為背景的另一個控件就不需要慢慢畫出,只要完全畫出來就行了。所以,猜想這里這個判斷條件就是判斷當(dāng)前控件是不是要隨圓形刷出的控件,如果不是,就直接畫出來就行了。所以修改代碼如下:

protected boolean drawChild(Canvas canvas, View paramView, long paramLong) {
if (drawBackground(paramView)) {
return super.drawChild(canvas, paramView, paramLong);
}
int i = canvas.save();
mPath.reset();
mPath.addCircle(mCenterX, mCenterY, mRevealRadius, Path.Direction.CW);
canvas.clipPath(this.mPath);
boolean bool2 = super.drawChild(canvas, paramView, paramLong);
canvas.restoreToCount(i);
return bool2;
}

判斷的方法如下:

private boolean drawBackground(View paramView) {
if (mIsFollowed && paramView == mUnFollowTv) {
return true;
} else if (!mIsFollowed && paramView == mFollowTv) {
return true;
}
return false;
}

至此,整個效果就和知乎完全一樣了,刷新過程行云流水,非常贊。效果如下










實現(xiàn)代碼已上傳至github:

https://github.com/zgzczzw/ZHFollowButton

以上所述是小編給大家介紹的Android仿知乎客戶端關(guān)注和取消關(guān)注的按鈕點擊特效實現(xiàn)思路詳解,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復(fù)大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!

相關(guān)文章

  • Android 如何使用短信鏈接打開APP

    Android 如何使用短信鏈接打開APP

    這篇文章主要介紹了Android 如何使用短信鏈接打開APP,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-03-03
  • Android編程根據(jù)系列圖片繪制動畫實例總結(jié)

    Android編程根據(jù)系列圖片繪制動畫實例總結(jié)

    這篇文章主要介紹了Android編程根據(jù)系列圖片繪制動畫的方法,以實例形式總結(jié)了Android根據(jù)圖片繪制動畫的常見情況與具體實現(xiàn)技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-11-11
  • Android  SharedPreferences四種操作模式使用詳解

    Android SharedPreferences四種操作模式使用詳解

    這篇文章主要介紹了Android SharedPreferences四種操作模式使用詳解的相關(guān)資料,這里介紹了獲取Android SharedPreferences的兩種方法及比較,和操作模式的介紹,需要的朋友可以參考下
    2017-07-07
  • Android 應(yīng)用指定瀏覽器開發(fā)實例

    Android 應(yīng)用指定瀏覽器開發(fā)實例

    這篇文章主要介紹了Android 應(yīng)用指定瀏覽器開發(fā)實例的相關(guān)資料,需要的朋友可以參考下
    2016-10-10
  • Flutter有狀態(tài)組件使用詳解

    Flutter有狀態(tài)組件使用詳解

    這篇文章主要為大家詳細(xì)介紹了Flutter有狀態(tài)組件的使用,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • Android使用ContentResolver搜索手機通訊錄的方法

    Android使用ContentResolver搜索手機通訊錄的方法

    這篇文章主要介紹了Android使用ContentResolver搜索手機通訊錄的方法,結(jié)合實例形式分析了Android中ContentResolver操作手機通訊錄的具體步驟與相關(guān)實現(xiàn)技巧,需要的朋友可以參考下
    2016-01-01
  • 用原生VideoView進(jìn)行全屏播放時的問題

    用原生VideoView進(jìn)行全屏播放時的問題

    本篇文章主要介紹了用原生VideoView進(jìn)行全屏播放時的問題,具有一定的參考價值,下面跟著小編一起來看下吧
    2017-01-01
  • android自定義等級評分圓形進(jìn)度條

    android自定義等級評分圓形進(jìn)度條

    這篇文章主要為大家詳細(xì)介紹了android自定義等級評分圓形進(jìn)度條,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-07-07
  • Android利用ContentProvider獲取本地數(shù)據(jù)的方法

    Android利用ContentProvider獲取本地數(shù)據(jù)的方法

    這篇文章主要介紹了Android利用ContentProvider獲取本地數(shù)據(jù)的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-04-04
  • Android修改源碼解決Alertdialog觸摸對話框邊緣消失的問題

    Android修改源碼解決Alertdialog觸摸對話框邊緣消失的問題

    在開發(fā)的時候遇到一個問題,就是一觸摸對話框邊緣外部,對話框會自動消失。這個問題很糾結(jié)啊,查找了一下發(fā)現(xiàn)從Android 4.0開始,AlertDialog有了變化,就是在觸摸對話框邊緣外部,對話框會自動消失,查了源碼,找到解決辦法如下
    2013-11-11

最新評論

天祝| 定陶县| 基隆市| 海淀区| 福建省| 台东市| 乐亭县| 凤庆县| 宜兰县| 安义县| 福清市| 铜陵市| 延边| 云梦县| 安平县| 安福县| 额尔古纳市| 临湘市| 海阳市| 神池县| 通化县| 亳州市| 锦屏县| 腾冲县| 庆城县| 出国| 阿尔山市| 白银市| 定兴县| 江西省| 镇赉县| 安庆市| 阳原县| 阜平县| 共和县| 永胜县| 海口市| 大英县| 通山县| 延寿县| 达尔|