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;
//停止狀態(tài)
protected static final int STATUS_STOP = 1;
//ViewGroup寬高
protected int mWidth, mHeight;
//變化的marginTop值
protected int mSmoothMarginTop;
//默認狀態(tài)
protected int mStatus = STATUS_STOP;
//滾動時間間隔
protected int mDuration = 500;
//重復次數(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 結果
*/
protected boolean isOddCircle() {
return mRepeatTimes % 2 == 1;
}
先了解下成員變量,其中最重要的一個就是mSmoothMarginTop,相信很多人都知道一個View的marginTop可以設為負數(shù),這個負數(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);
}
關鍵點說明:
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;
}
//動畫結束
protected abstract void doAnimFinish();
//動畫進行時
protected abstract void doAnim();
關鍵點說明:
屬性動畫控制著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();
}
關鍵點說明:
通過mSmoothMarginTop與mHeight的比值控制陰影View的透明度
每次動畫完成時,下方的圖(此時下方的圖已經(jīng)超出屏幕了,而上方圖顯示在屏幕內(nèi))需要加載第三張圖,使用getImgPath()取出
pic1

以上就是圖片的滾動實現(xiàn),文字的滾動90%是一樣的,有點區(qū)別的就是需要文字需要控制下垂直居中,我就不贅述了。
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
- 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使用方法詳解
相關文章
Android 實現(xiàn)長按彈出PopupMenu 菜單欄
這篇文章主要介紹了Android 實現(xiàn)長按彈出PopupMenu 菜單欄,本文通過實例代碼給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下2019-12-12
Android開發(fā)之多線程中實現(xiàn)利用自定義控件繪制小球并完成小球自動下落功能實例
這篇文章主要介紹了Android開發(fā)之多線程中實現(xiàn)利用自定義控件繪制小球并完成小球自動下落功能的方法,涉及Android多線程編程及圖形繪制相關技巧,需要的朋友可以參考下2015-12-12
Android studio無法創(chuàng)建類和接口和提示問題的完美解決辦法
這篇文章主要介紹了Android studio無法創(chuàng)建類和接口和提示問題解決辦法,內(nèi)容比較簡單,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2018-04-04
Android自定義View實現(xiàn)游戲搖桿鍵盤的方法示例
Android進階過程中有一個繞不開的話題——自定義View。最近在做項目中又遇到了,所以下面這篇文章主要給大家介紹了利用Android自定義View實現(xiàn)游戲搖桿鍵盤的相關資料,操作方式類似王者榮耀的搖桿操作,文中通過示例代碼介紹的非常詳細,需要的朋友們下面來一起看看吧。2017-07-07
使用Android Studio Gradle實現(xiàn)友盟多渠道打包
這篇文章主要介紹了使用Android Studio Gradle實現(xiàn)友盟多渠道打包,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-05-05

