前言
成都創(chuàng)新互聯(lián)專注于龍鳳企業(yè)網(wǎng)站建設(shè),成都響應(yīng)式網(wǎng)站建設(shè)公司,商城開發(fā)。龍鳳網(wǎng)站建設(shè)公司,為龍鳳等地區(qū)提供建站服務(wù)。全流程按需求定制制作,專業(yè)設(shè)計,全程項目跟蹤,成都創(chuàng)新互聯(lián)專業(yè)和態(tài)度為您提供的服務(wù)
面對眾多卡片層疊效果,我們的產(chǎn)品童鞋也突發(fā)奇想,搞出了另一種卡片層疊切換展示的交互,而且產(chǎn)品狗們居然要求多做幾種動效給他們看,好讓他們選擇,這簡直就是要搞事情啊,what are you 弄啥咧?!
“哥哥我做不到啊.....啊.....呸”,做為一名有節(jié)操的程序猿,自然是不能說出這么沒有出息的話,哥就滿足你們,于是,出了個可自定義動效的卡片切換視圖,效果如下所示
思路
首先,要展示出卡片層疊的視覺效果。在這里,我們通過方塊的縮放大小差異以及在Y方向上的位置差異,來展現(xiàn)這種視覺效果。
其次,要能夠方便的定義卡片視圖內(nèi)容。我們通過都很熟悉的設(shè)置Adapter的方式來構(gòu)建內(nèi)容視圖。
最后,要能夠自定義動效。我們通過定義一個由0到1的ValueAnimator,即每個動畫的過程,其實就是該ValueAnimator在一個動畫周期內(nèi),從0變化到1的過程,0表示動畫剛開始,1表示動畫結(jié)束了,0.5則表示這一輪動畫已經(jīng)執(zhí)行到了一半。這樣,通過轉(zhuǎn)換器以及插值器,我們就可以根據(jù)ValueAnimator實時的值,來設(shè)置當前正在執(zhí)行動畫的卡片應(yīng)該有的“樣子”。
總覽
我們給出三種基本的動畫模式
/* * ANIM_TYPE_FRONT:被選中的卡片通過自定義動效移至第一,其他的卡片通過通用動效補位 * ANIM_TYPE_SWITCH:選中的卡片和第一張卡片互換位置,并都是自定義動效 * ANIM_TYPE_FRONT_TO_LAST:第一張圖片通過自定義動效移至最后,其他卡片通過通用動效補位 */ public static final int ANIM_TYPE_FRONT = 0, ANIM_TYPE_SWITCH = 1, ANIM_TYPE_FRONT_TO_LAST = 2;
并通過Helper類來處理所有的動畫邏輯,以及Adapter來生成卡片視圖
private CardAnimationHelper mAnimationHelper; private BaseAdapter mAdapter;
在onMeasure時根據(jù)卡片寬高比來設(shè)置卡片的尺寸,在此請注意,當前情況下卡片寬度與整體容器寬度一致,后續(xù)通過自定義的方式,通過縮放來產(chǎn)生卡片的視覺效果。
private float mCardRatio = CARD_SIZE_RATIO;//寬高比:卡片高 / 卡片寬 private int mCardWidth, mCardHeight;//卡片寬高 @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { ... if (mCardWidth == 0 || mCardHeight == 0) { setCardSize(true); } } /* * 根據(jù)卡片比例計算卡片寬高,并傳入Helper */ private void setCardSize(boolean resetAdapter) { mCardWidth = getMeasuredWidth(); mCardHeight = (int) (mCardWidth * mCardRatio); mAnimationHelper.setCardSize(mCardWidth, mCardHeight); mAnimationHelper.initAdapterView(mAdapter, resetAdapter); }
那么如此之后,自然Helper中就保存了視圖的主要數(shù)據(jù)與參數(shù)
//卡片列表 private LinkedList<CardItem> mCards; //當前正在向后以及向前移動的卡片 private CardItem mCardToBack, mCardToFront; //正在向后以及向前移動卡片的位置 private int mPositionToBack = 0, mPositionToFront = 0; //動畫運行的ValueAnimator private ValueAnimator mValueAnimator; //當前的動畫系數(shù) private float mCurrentFraction = 1; ...//以及一系列的轉(zhuǎn)換器與插值器
細節(jié)
那么,動畫到底是如何實現(xiàn)的,以及如何自定義的呢,我們以通用動畫為例,來看看動畫的主要流程
首先,在ValueAnimator更新的時候,獲得當前的動畫系數(shù),依次來執(zhí)行動畫
/** * ValueAnimator動畫更新 */ @Override public void onAnimationUpdate(ValueAnimator animation) { //獲取當前動畫系數(shù) mCurrentFraction = (float) animation.getAnimatedValue(); //通過插值器獲取插值系數(shù) fractionInterpolated = mAnimInterpolator.getInterpolation(mCurrentFraction); doAnimationCommon(mCurrentFraction, fractionInterpolated); ... }
接著,對需要執(zhí)行動畫的卡片,執(zhí)行動畫,以ANIM_TYPE_FRONT動畫模式為例,當選中的卡片移動到最前的時候,原來在這張卡片之前的所有卡片,都要向后移動一位,來留出第一個的位置
/** * 執(zhí)行通用動畫 */ private void doAnimationCommon(float fraction, float fractionInterpolated) { //如果當前動畫模式為選中的卡片移到最前 if (mAnimType == InfiniteCardView.ANIM_TYPE_FRONT) { //則遍歷在選中卡片之前的卡片 for (int i = 0; i < mPositionToFront; i++) { CardItem card = mCards.get(i); //對卡片執(zhí)行動畫,從當前位置移動到后一個位置 doAnimationCommonView(card.view, fraction, fractionInterpolated, i, i + 1); ... } }... }
最后,通過轉(zhuǎn)換器,對卡片進行自定義動畫處理
/** * 對視圖執(zhí)行通用動畫 * @param view 卡片視圖 * @param fromPosition 從該位置 * @param toPosition 移動到該位置 */ private void doAnimationCommonView(View view, float fraction, float fractionInterpolated, int fromPosition, int toPosition) { //通用轉(zhuǎn)換器轉(zhuǎn)換動畫 mTransformerCommon.transformAnimation(view, fraction, mCardWidth, mCardHeight, fromPosition, toPosition); if (mAnimInterpolator != null) { //通用轉(zhuǎn)換器轉(zhuǎn)換插值動畫 mTransformerCommon.transformInterpolatedAnimation(view, fractionInterpolated, mCardWidth,mCardHeight, fromPosition, toPosition); } }
而轉(zhuǎn)換器的具體實現(xiàn)則以DefaultCommonTransformer為例
@Override public void transformAnimation(View view, float fraction, int cardWidth, int cardHeight, int fromPosition, int toPosition) { //需要跨越的卡片數(shù)量 int positionCount = fromPosition - toPosition; //以0.8做為第一張的縮放尺寸,每向后一張縮小0.1 //(0.8f - 0.1f * fromPosition) = 當前位置的縮放尺寸 //(0.1f * fraction * positionCount) = 移動過程中需要改變的縮放尺寸 float scale = (0.8f - 0.1f * fromPosition) + (0.1f * fraction * positionCount); ViewHelper.setScaleX(view, scale); ViewHelper.setScaleY(view, scale); //在Y方向的偏移量,每向后一張,向上偏移卡片寬度的0.02 //-cardHeight * (0.8f - scale) * 0.5f 對卡片做整體居中處理 ViewHelper.setTranslationY(view, -cardHeight * (0.8f - scale) * 0.5f - cardWidth * (0.02f * fromPosition - 0.02f * fraction * positionCount)); }
對于向第一位移動的選中卡片,也是同理,只不過是根據(jù)該卡片對應(yīng)的轉(zhuǎn)換器來進行自定義動畫的轉(zhuǎn)換。
最后的效果,就像演示圖中第一次點擊,圖片向前翻轉(zhuǎn)到第一位的效果一樣。
對于產(chǎn)品狗突如其來的想法,咱們程序猿不善于口水仗的,就只能用代碼來讓他們來服氣了。畢竟,大家還都是伐木累嘛,哈哈。
當實現(xiàn)某個東西遇到困難時,不妨想想Android系統(tǒng)自身的一些實現(xiàn)方式,比如參考ListView的Adapter,ViewPager定義翻頁動畫的Transformer等等,總會有意想不到的啟發(fā)。
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學習或者工作具有一定的參考學習價值,謝謝大家對創(chuàng)新互聯(lián)的支持。如果你想了解更多相關(guān)內(nèi)容請查看下面相關(guān)鏈接
當前標題:Android可自定義神奇動效的卡片切換視圖實例
文章分享:http://jinyejixie.com/article48/pgeshp.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供外貿(mào)建站、品牌網(wǎng)站制作、網(wǎng)站維護、定制開發(fā)、網(wǎng)站內(nèi)鏈、企業(yè)建站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)