Android仿即刻首頁垂直滾動圖,炫酷到底!
項目地址:https://github.com/JeasonWong/JikeGallery
話不多說,先上效果。
這個效果是在即刻app上看到,覺得很不錯,遂仿之。
先說下我的實現(xiàn)思路(以上方的圖片滾動為例,下方的文字實現(xiàn)效果類似):
自定義ViewGroup
裝載兩個ImageView和一個陰影View
通過一定規(guī)律交替控制兩個ImageView和它們的marginTop,在onLayout()中實現(xiàn)
marginTop的具體值由屬性動畫控制,不斷調(diào)用requestLayout()
接下來依次說明
一、自定義ViewGroup
//滑動狀態(tài) protected static final int STATUS_SMOOTHING = 0; //停止?fàn)顟B(tài) protected static final int STATUS_STOP = 1; //ViewGroup寬高 protected int mWidth, mHeight; //變化的marginTop值 protected int mSmoothMarginTop; //默認(rèn)狀態(tài) protected int mStatus = STATUS_STOP; //滾動時間間隔 protected int mDuration = 500; //重復(fù)次數(shù) protected int mRepeatTimes = 0; ... @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); mWidth = w; mHeight = h; mSmoothMarginTop = -h; initView(); } protected abstract void initView(); ... /** * 是否是奇數(shù)圈 * * @return 結(jié)果 */ protected boolean isOddCircle() { return mRepeatTimes % 2 == 1; }
先了解下成員變量,其中最重要的一個就是mSmoothMarginTop,相信很多人都知道一個View的marginTop可以設(shè)為負(fù)數(shù),這個負(fù)數(shù)可以給我們帶來太多的方便。
上圖的圖0就是我們展現(xiàn)在屏幕上的ImageView,圖1則是屏幕外marginTop為-height的ImageView,這個一定要明白,接下來才好繼續(xù)實現(xiàn)。
二、裝載兩個ImageView和一個陰影View
private List<String> mImgList = new ArrayList<>(); private ImageView[] mImgs = new ImageView[2]; private View mShadowView; ... @Override protected void initView() { //如果沒有內(nèi)容,則不進行初始化操作 if (mImgList.size() == 0) { return; } removeAllViews(); MarginLayoutParams params = new MarginLayoutParams(mWidth, mHeight); //兩個ImageView加載前兩張圖 for (int i = 0; i < mImgs.length; i++) { mImgs[i] = new ImageView(getContext()); addViewInLayout(mImgs[i], -1, params, true); Glide.with(getContext()).load(getImgPath(i)).centerCrop().into(mImgs[i]); } //創(chuàng)建陰影View mShadowView = new View(getContext()); mShadowView.setBackgroundColor(Color.parseColor("#60000000")); mShadowView.setAlpha(0); addViewInLayout(mShadowView, -1, params, true); } ... /** * 獲取圖片地址 * * @param position 位置 * @return 圖片地址 */ private String getImgPath(int position) { position = position % mImgList.size(); return mImgList.get(position); }
關(guān)鍵點說明:
MarginLayoutParams 為了之后方便取出margin值
addViewInLayout() 為了對requestLayout的絕對控制
getImgPath() 為了實現(xiàn)循環(huán)滾動
這樣一來,我們需要的View都已經(jīng)創(chuàng)建好了。
三、通過一定規(guī)律交替控制兩個ImageView和它們的marginTop,在onLayout()中實現(xiàn)
@Override protected void onLayout(boolean changed, int l, int t, int r, int b) { int cCount = getChildCount(); MarginLayoutParams cParams; for (int i = 0; i < cCount; i++) { View childView = getChildAt(i); cParams = (MarginLayoutParams) childView.getLayoutParams(); int cl = 0, ct = 0, cr, cb; if (isOddCircle()) { if (i == 1) { cl = cParams.leftMargin; ct = mSmoothMarginTop + mHeight; } else if (i == 0) { cl = cParams.leftMargin; ct = mSmoothMarginTop; } } else { if (i == 0) { cl = cParams.leftMargin; ct = mSmoothMarginTop + mHeight; } else if (i == 1) { cl = cParams.leftMargin; ct = mSmoothMarginTop; } } //控制shadowView if (i == 2) { cl = cParams.leftMargin; ct = mSmoothMarginTop + mHeight; } cr = cl + mWidth; cb = ct + mHeight; childView.layout(cl, ct, cr, cb); } }
以上實現(xiàn)的就是不斷的替換圖1和圖2誰上誰下,陰影和下方的圖保持同步。
四、marginTop的具體值由屬性動畫控制,不斷調(diào)用requestLayout()
先看基類ViewGroup
/** * 開啟滑動 * */ public void startSmooth() { if (mStatus != STATUS_STOP) { return; } ValueAnimator animator = ValueAnimator.ofFloat(-mHeight, 0); animator.setDuration(mDuration); animator.setInterpolator(new AccelerateDecelerateInterpolator()); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float marginTop = (float) animation.getAnimatedValue(); mSmoothMarginTop = (int) marginTop; if (marginTop == 0) { postDelayed(new Runnable() { @Override public void run() { mRepeatTimes++; mSmoothMarginTop = -mHeight; doAnimFinish(); mStatus = STATUS_STOP; } }, 50); } else { doAnim(); } } }); animator.start(); mStatus = STATUS_SMOOTHING; } //動畫結(jié)束 protected abstract void doAnimFinish(); //動畫進行時 protected abstract void doAnim();
關(guān)鍵點說明:
屬性動畫控制著mSmoothMarginTop在[-mHeight, 0]中變化
每完成一圈,mRepeatTimes自增1
再來看看Gallery實現(xiàn)類
@Override protected void doAnimFinish() { if (isOddCircle()) { Glide.with(getContext()).load(getImgPath(mRepeatTimes + 1)).centerCrop().into(mImgs[0]); } else { Glide.with(getContext()).load(getImgPath(mRepeatTimes + 1)).centerCrop().into(mImgs[1]); } mShadowView.setAlpha(0); } @Override protected void doAnim() { mShadowView.setAlpha(((1 - (-mSmoothMarginTop) / (float) mHeight))); requestLayout(); }
關(guān)鍵點說明:
通過mSmoothMarginTop與mHeight的比值控制陰影View的透明度
每次動畫完成時,下方的圖(此時下方的圖已經(jīng)超出屏幕了,而上方圖顯示在屏幕內(nèi))需要加載第三張圖,使用getImgPath()取出
pic1
以上就是圖片的滾動實現(xiàn),文字的滾動90%是一樣的,有點區(qū)別的就是需要文字需要控制下垂直居中,我就不贅述了。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Android中實現(xiàn)監(jiān)聽ScrollView滑動事件
- 在android中ScrollView嵌套ScrollView解決方案
- android TextView不用ScrollViewe也可以滾動的方法
- android 實現(xiàn)ScrollView自動滾動的實例代碼
- Android之ScrollView嵌套ListView和GridView沖突的解決方法
- android 自定義ScrollView實現(xiàn)背景圖片伸縮的實現(xiàn)代碼及思路
- android開發(fā)教程之文本框加滾動條scrollview
- Android TextView實現(xiàn)垂直滾動效果的方法
- Android實現(xiàn)Activity水平和垂直滾動條的方法
- Android垂直滾動控件ScrollView使用方法詳解
相關(guān)文章
a2sd+狀態(tài)下應(yīng)用程序丟失的解決方法詳細解析
用了a2sd+和SD分區(qū)方案的朋友可能會遇到突然某次開機之后,a2sd+失效,同時發(fā)生丟失若干應(yīng)用程序的現(xiàn)象或者安裝軟件提示空間不足2013-09-09Android 實現(xiàn)長按彈出PopupMenu 菜單欄
這篇文章主要介紹了Android 實現(xiàn)長按彈出PopupMenu 菜單欄,本文通過實例代碼給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下2019-12-12Android開發(fā)之多線程中實現(xiàn)利用自定義控件繪制小球并完成小球自動下落功能實例
這篇文章主要介紹了Android開發(fā)之多線程中實現(xiàn)利用自定義控件繪制小球并完成小球自動下落功能的方法,涉及Android多線程編程及圖形繪制相關(guān)技巧,需要的朋友可以參考下2015-12-12Android studio無法創(chuàng)建類和接口和提示問題的完美解決辦法
這篇文章主要介紹了Android studio無法創(chuàng)建類和接口和提示問題解決辦法,內(nèi)容比較簡單,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2018-04-04Android自定義View實現(xiàn)游戲搖桿鍵盤的方法示例
Android進階過程中有一個繞不開的話題——自定義View。最近在做項目中又遇到了,所以下面這篇文章主要給大家介紹了利用Android自定義View實現(xiàn)游戲搖桿鍵盤的相關(guān)資料,操作方式類似王者榮耀的搖桿操作,文中通過示例代碼介紹的非常詳細,需要的朋友們下面來一起看看吧。2017-07-07使用Android Studio Gradle實現(xiàn)友盟多渠道打包
這篇文章主要介紹了使用Android Studio Gradle實現(xiàn)友盟多渠道打包,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-05-05