編輯:關於Android編程
項目地址:https://github.com/JeasonWong/JikeGallery
話不多說,先上效果。
這個效果是在即刻app上看到,覺得很不錯,遂仿之。
先說下我的實現思路(以上方的圖片滾動為例,下方的文字實現效果類似):
自定義ViewGroup
裝載兩個ImageView和一個陰影View
通過一定規律交替控制兩個ImageView和它們的marginTop,在onLayout()中實現
marginTop的具體值由屬性動畫控制,不斷調用requestLayout()
接下來依次說明
一、自定義ViewGroup
//滑動狀態 protected static final int STATUS_SMOOTHING = 0; //停止狀態 protected static final int STATUS_STOP = 1; //ViewGroup寬高 protected int mWidth, mHeight; //變化的marginTop值 protected int mSmoothMarginTop; //默認狀態 protected int mStatus = STATUS_STOP; //滾動時間間隔 protected int mDuration = 500; //重復次數 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(); ... /** * 是否是奇數圈 * * @return 結果 */ protected boolean isOddCircle() { return mRepeatTimes % 2 == 1; }
先了解下成員變量,其中最重要的一個就是mSmoothMarginTop,相信很多人都知道一個View的marginTop可以設為負數,這個負數可以給我們帶來太多的方便。
上圖的圖0就是我們展現在屏幕上的ImageView,圖1則是屏幕外marginTop為-height的ImageView,這個一定要明白,接下來才好繼續實現。
二、裝載兩個ImageView和一個陰影View
private List<String> mImgList = new ArrayList<>(); private ImageView[] mImgs = new ImageView[2]; private View mShadowView; ... @Override protected void initView() { //如果沒有內容,則不進行初始化操作 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]); } //創建陰影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() 為了實現循環滾動
這樣一來,我們需要的View都已經創建好了。
三、通過一定規律交替控制兩個ImageView和它們的marginTop,在onLayout()中實現
@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); } }
以上實現的就是不斷的替換圖1和圖2誰上誰下,陰影和下方的圖保持同步。
四、marginTop的具體值由屬性動畫控制,不斷調用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實現類
@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的透明度
每次動畫完成時,下方的圖(此時下方的圖已經超出屏幕了,而上方圖顯示在屏幕內)需要加載第三張圖,使用getImgPath()取出
pic1
以上就是圖片的滾動實現,文字的滾動90%是一樣的,有點區別的就是需要文字需要控制下垂直居中,我就不贅述了。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持本站。
現在分頁加載在apk中應用廣泛 那麼是怎麼實現的呢 下面讓我們舉一個小例子來看一下 首先是我們的自定義的listview 在布局中引用 那麼就看一下我們的布局文
ListIterator根據官方文檔介紹, ListIterator 有以下功能:允許我們向前、向後兩個方向遍歷 List; 在遍歷時修改 List 的元素; 遍歷時獲取
MainActivity.java代碼:package siso.mycrawler;import android.app.Activity;import android
在工作中,曾多次碰到ScrollView嵌套ListView的問題,網上的解決方法有很多種,但是雜而不全。我試過很多種方法,它們各有利弊。 在這裡我將會從使用Sc