a亚洲精品_精品国产91乱码一区二区三区_亚洲精品在线免费观看视频_欧美日韩亚洲国产综合_久久久久久久久久久成人_在线区

首頁 > 系統 > Android > 正文

Android可自定義神奇動效的卡片切換視圖實例

2019-10-21 21:25:32
字體:
來源:轉載
供稿:網友

前言

面對眾多卡片層疊效果,我們的產品童鞋也突發奇想,搞出了另一種卡片層疊切換展示的交互,而且產品狗們居然要求多做幾種動效給他們看,好讓他們選擇,這簡直就是要搞事情啊,what are you 弄啥咧?!

“哥哥我做不到啊.....啊.....呸”,做為一名有節操的程序猿,自然是不能說出這么沒有出息的話,哥就滿足你們,于是,出了個可自定義動效的卡片切換視圖,效果如下所示

Android,動效,卡片切換視圖

思路

首先,要展示出卡片層疊的視覺效果。在這里,我們通過方塊的縮放大小差異以及在Y方向上的位置差異,來展現這種視覺效果。

其次,要能夠方便的定義卡片視圖內容。我們通過都很熟悉的設置Adapter的方式來構建內容視圖。

最后,要能夠自定義動效。我們通過定義一個由0到1的ValueAnimator,即每個動畫的過程,其實就是該ValueAnimator在一個動畫周期內,從0變化到1的過程,0表示動畫剛開始,1表示動畫結束了,0.5則表示這一輪動畫已經執行到了一半。這樣,通過轉換器以及插值器,我們就可以根據ValueAnimator實時的值,來設置當前正在執行動畫的卡片應該有的“樣子”。

總覽

我們給出三種基本的動畫模式

/* * 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時根據卡片寬高比來設置卡片的尺寸,在此請注意,當前情況下卡片寬度與整體容器寬度一致,后續通過自定義的方式,通過縮放來產生卡片的視覺效果。

private float mCardRatio = CARD_SIZE_RATIO;//寬高比:卡片高 / 卡片寬private int mCardWidth, mCardHeight;//卡片寬高@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  ...  if (mCardWidth == 0 || mCardHeight == 0) {    setCardSize(true);  }}/* * 根據卡片比例計算卡片寬高,并傳入Helper */private void setCardSize(boolean resetAdapter) {  mCardWidth = getMeasuredWidth();  mCardHeight = (int) (mCardWidth * mCardRatio);  mAnimationHelper.setCardSize(mCardWidth, mCardHeight);  mAnimationHelper.initAdapterView(mAdapter, resetAdapter);}

那么如此之后,自然Helper中就保存了視圖的主要數據與參數

//卡片列表private LinkedList<CardItem> mCards;//當前正在向后以及向前移動的卡片private CardItem mCardToBack, mCardToFront;//正在向后以及向前移動卡片的位置private int mPositionToBack = 0, mPositionToFront = 0;//動畫運行的ValueAnimatorprivate ValueAnimator mValueAnimator;//當前的動畫系數private float mCurrentFraction = 1;...//以及一系列的轉換器與插值器

細節

那么,動畫到底是如何實現的,以及如何自定義的呢,我們以通用動畫為例,來看看動畫的主要流程

首先,在ValueAnimator更新的時候,獲得當前的動畫系數,依次來執行動畫

/** * ValueAnimator動畫更新 */@Overridepublic void onAnimationUpdate(ValueAnimator animation) {  //獲取當前動畫系數  mCurrentFraction = (float) animation.getAnimatedValue();  //通過插值器獲取插值系數  fractionInterpolated = mAnimInterpolator.getInterpolation(mCurrentFraction);  doAnimationCommon(mCurrentFraction, fractionInterpolated);  ...}

接著,對需要執行動畫的卡片,執行動畫,以ANIM_TYPE_FRONT動畫模式為例,當選中的卡片移動到最前的時候,原來在這張卡片之前的所有卡片,都要向后移動一位,來留出第一個的位置

/** * 執行通用動畫 */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);      //對卡片執行動畫,從當前位置移動到后一個位置      doAnimationCommonView(card.view, fraction, fractionInterpolated, i, i + 1);      ...    }  }...}

最后,通過轉換器,對卡片進行自定義動畫處理

/** * 對視圖執行通用動畫 * @param view         卡片視圖 * @param fromPosition     從該位置 * @param toPosition      移動到該位置 */private void doAnimationCommonView(View view, float fraction, float fractionInterpolated, int    fromPosition, int toPosition) {  //通用轉換器轉換動畫  mTransformerCommon.transformAnimation(view, fraction, mCardWidth,      mCardHeight, fromPosition, toPosition);  if (mAnimInterpolator != null) {    //通用轉換器轉換插值動畫    mTransformerCommon.transformInterpolatedAnimation(view, fractionInterpolated,            mCardWidth,mCardHeight, fromPosition, toPosition);  }}

而轉換器的具體實現則以DefaultCommonTransformer為例

@Overridepublic void transformAnimation(View view, float fraction, int cardWidth, int cardHeight, int fromPosition, int toPosition) {  //需要跨越的卡片數量  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));}

對于向第一位移動的選中卡片,也是同理,只不過是根據該卡片對應的轉換器來進行自定義動畫的轉換。

最后的效果,就像演示圖中第一次點擊,圖片向前翻轉到第一位的效果一樣。

對于產品狗突如其來的想法,咱們程序猿不善于口水仗的,就只能用代碼來讓他們來服氣了。畢竟,大家還都是伐木累嘛,哈哈。

當實現某個東西遇到困難時,不妨想想Android系統自身的一些實現方式,比如參考ListView的Adapter,ViewPager定義翻頁動畫的Transformer等等,總會有意想不到的啟發。

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,謝謝大家對VEVB武林網的支持。


注:相關教程知識閱讀請移步到Android開發頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 天堂va蜜桃一区二区三区 | 国产欧美精品区一区二区三区 | 午夜影院18 | 国产精品日韩欧美一区二区三区 | 欧美日韩精品免费 | 亚洲成人免费网址 | 性视频一区二区 | aaaa大片| 欧洲一区二区视频 | 久久久精品视频在线观看 | 国产精品久久久久aaaa九色 | 久久精品这里热有精品 | 91久久久久 | 亚洲欧美综合精品久久成人 | aaa在线观看| 国产日韩欧美精品一区二区 | 亚洲精品在线播放 | 欧美一区二区三区aa大片漫 | 污网站在线看 | 国产一级片一区二区三区 | 国产精品久久久久久久免费大片 | 久久久精品国产 | 欧美日韩国产精品 | 日韩成人精品在线 | 在线播放一区二区三区 | 亚洲精品自拍视频 | 99色影院| 免费黄色看片 | 亚洲444kkkk在线观看最新 | 成人在线播放器 | 亚洲成人黄色网 | 国产999精品久久久久久 | 国产精品二区三区 | 国产精品.xx视频.xxtv | 成人福利网| 久久国产黄色片 | 国产1页| 免费a视频在线 | 成人爽a毛片一区二区免费 美女一级毛片 | av电影手机在线看 | 国产欧美在线观看 |