Android--仿愛奇藝 首頁輪播圖
阿新 • • 發佈:2018-12-22
前因
近期開啟愛奇藝的時候,突然發現它首頁的輪播圖跟以前不一樣了,左右兩個圖都能顯示一部分,且有滑動時縮放的效果,一直不知咋樣實現,然後在鴻洋的微信公眾號中看到了一篇仿魅族Banner效果的文章,最後在參考中放出了連結,然後就參考了這篇文章,就在此做個記錄。廢話不多說了,先上個效果圖
後果
佈局檔案
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false"
android:orientation="vertical">
<com.ly.viewpagerdemo.LoopViewPager
android:id="@+id/looviewpager"
android:layout_width="match_parent"
android:layout_height="200dp"
android:layout_marginLeft ="20dp"
android:layout_marginRight="20dp" />
</LinearLayout>
這個屬性android:clipChildren 很關鍵,是否裁剪子view
這裡的LoopViewPager,是參考開源框架 LoopingViewPager來的,使用Integer.MAX_VALUE 來實現左右迴圈滾動的,使用方式是一致的
package com.ly.viewpagerdemo;
import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.WindowManager;
import android.view.animation.Interpolator;
import android.widget.Scroller;
import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.util.concurrent.atomic.AtomicBoolean;
public class LoopViewPager extends ViewPager {
OnPageChangeListener mOuterPageChangeListener;
private LoopPagerAdapterWrapper mAdapter;
private MyHandler mHandler;
private final static int HANDLE_LOOP_MSG = 101;
private AtomicBoolean isAutoLoop = new AtomicBoolean();
@Override
public void setAdapter(PagerAdapter adapter) {
mAdapter = new LoopPagerAdapterWrapper(adapter);
super.setAdapter(mAdapter);
isAutoLoop.set(false);
setCurrentItem(0, false);
}
@Override
public PagerAdapter getAdapter() {
return mAdapter != null ? mAdapter.getRealAdapter() : mAdapter;
}
/**
* 獲取當前真實的item
*
* @return
*/
public int getRealItem() {
return mAdapter != null ? mAdapter.toRealPosition(super.getCurrentItem()) : 0;
}
public void setCurrentItem(int item, boolean smoothScroll) {
int realItem = mAdapter.toInnerPosition(item);
super.setCurrentItem(realItem, smoothScroll);
}
@Override
public void setOnPageChangeListener(OnPageChangeListener listener) {
mOuterPageChangeListener = listener;
}
public LoopViewPager(Context context) {
super(context);
init();
}
public LoopViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
super.setOnPageChangeListener(onPageChangeListener);
try {
Field scrollerField = ViewPager.class.getDeclaredField("mScroller");
scrollerField.setAccessible(true);
Field interpolator = ViewPager.class.getDeclaredField("sInterpolator");
interpolator.setAccessible(true);
Scroller scroller = new Scroller(getContext(), (Interpolator) interpolator.get(null)) {
@Override
public void startScroll(int startX, int startY, int dx, int dy, int duration) {
//控制滑動速度
super.startScroll(startX, startY, dx, dy, (int) (1300 * (double) Math.abs(dx) / getWidth(getContext())));
}
};
scrollerField.set(this, scroller);
} catch (Exception e) {
e.printStackTrace();
}
}
public void autoLoop(boolean isAuto) {
if (mHandler == null) {
mHandler = new MyHandler(getContext());
}
if (isAuto) {
mHandler.sendEmptyMessageDelayed(HANDLE_LOOP_MSG, 3000);
} else {
mHandler.removeCallbacksAndMessages(null);
}
isAutoLoop.set(isAuto);
}
private OnPageChangeListener onPageChangeListener = new OnPageChangeListener() {
private float mPreviousOffset = -1;
private float mPreviousPosition = -1;
@Override
public void onPageSelected(int position) {
int realPosition = mAdapter.toRealPosition(position);
if (mPreviousPosition != realPosition) {
mPreviousPosition = realPosition;
if (mOuterPageChangeListener != null) {
mOuterPageChangeListener.onPageSelected(realPosition);
}
}
}
@Override
public void onPageScrolled(int position, float positionOffset,
int positionOffsetPixels) {
int realPosition = position;
if (mAdapter != null) {
realPosition = mAdapter.toRealPosition(position);
if (positionOffset == 0
&& mPreviousOffset == 0
&& (position == 0 || position == mAdapter.getCount() - 1)) {
setCurrentItem(realPosition, false);
}
}
mPreviousOffset = positionOffset;
if (mOuterPageChangeListener != null) {
if (realPosition != mAdapter.getRealCount() - 1) {
mOuterPageChangeListener.onPageScrolled(realPosition,
positionOffset, positionOffsetPixels);
} else {
if (positionOffset > .5) {
mOuterPageChangeListener.onPageScrolled(0, 0, 0);
} else {
mOuterPageChangeListener.onPageScrolled(realPosition,
0, 0);
}
}
}
}
@Override
public void onPageScrollStateChanged(int state) {
switch (state) {
case SCROLL_STATE_DRAGGING:
if (isAutoLoop.get()) {
mHandler.removeCallbacksAndMessages(null);
}
break;
case SCROLL_STATE_IDLE:
if (isAutoLoop.get()) {
mHandler.sendEmptyMessageDelayed(HANDLE_LOOP_MSG, 3000);
}
break;
case SCROLL_STATE_SETTLING:
break;
}
if (mOuterPageChangeListener != null) {
mOuterPageChangeListener.onPageScrollStateChanged(state);
}
}
};
private class MyHandler extends Handler {
WeakReference<Context> mWeakReference;
public MyHandler(Context context) {
mWeakReference = new WeakReference<>(context);
}
@Override
public void handleMessage(Message msg) {
final Context context = mWeakReference.get();
if (context == null) {
return;
}
switch (msg.what) {
case HANDLE_LOOP_MSG:
int curItem = getCurrentItem();
setCurrentItem(++curItem);
break;
}
}
}
public int getWidth(Context context) {
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics outMetrics = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(outMetrics);
return outMetrics.widthPixels;
}
}
LoopPagerAdapterWrapper
package com.ly.viewpagerdemo;
import android.os.Parcelable;
import android.support.v4.view.PagerAdapter;
import android.view.View;
import android.view.ViewGroup;
public class LoopPagerAdapterWrapper extends PagerAdapter {
private PagerAdapter mAdapter;
LoopPagerAdapterWrapper(PagerAdapter adapter) {
this.mAdapter = adapter;
}
@Override
public void notifyDataSetChanged() {
super.notifyDataSetChanged();
}
public int toInnerPosition(int realPosition) {
return realPosition + getCount() / 2 - getCount() % getRealCount();
}
int toRealPosition(int position) {
return position % getRealCount();
}
@Override
public int getCount() {
return Integer.MAX_VALUE;
}
public int getRealCount() {
return mAdapter.getCount();
}
public PagerAdapter getRealAdapter() {
return mAdapter;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
int realPosition = position % getRealCount();
return mAdapter.instantiateItem(container, realPosition);
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
int realPosition = position % getRealCount();
mAdapter.destroyItem(container, realPosition, object);
}
@Override
public void finishUpdate(ViewGroup container) {
mAdapter.finishUpdate(container);
}
@Override
public boolean isViewFromObject(View view, Object object) {
return mAdapter.isViewFromObject(view, object);
}
@Override
public void restoreState(Parcelable bundle, ClassLoader classLoader) {
mAdapter.restoreState(bundle, classLoader);
}
@Override
public Parcelable saveState() {
return mAdapter.saveState();
}
@Override
public void startUpdate(ViewGroup container) {
mAdapter.startUpdate(container);
}
@Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
mAdapter.setPrimaryItem(container, position, object);
}
}
MainActivity
package com.ly.viewpagerdemo;
import android.content.Context;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
public class MainActivity extends AppCompatActivity {
private LoopViewPager looviewpager;
Context context;
int[] resIds = new int[]{R.mipmap.img1, R.mipmap.img2, R.mipmap.img3, R.mipmap.img4, R.mipmap.img5, R.mipmap.img6};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
context = this;
looviewpager = (LoopViewPager) findViewById(R.id.looviewpager);
looviewpager.setAdapter(new MyAdapter());
looviewpager.setOffscreenPageLimit(3);
looviewpager.setPageTransformer(true, new ViewPager.PageTransformer() {
float scale = 0.9f;
@Override
public void transformPage(View page, float position) {
if (position >= 0 && position <= 1) {
page.setScaleY(scale + (1 - scale) * (1 - position));
} else if (position > -1 && position < 0) {
page.setScaleY(1 + (1 - scale) * position);
} else {
page.setScaleY(scale);
}
}
});
looviewpager.autoLoop(true);
}
class MyAdapter extends PagerAdapter {
@Override
public int getCount() {
return resIds.length;
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
View view = View.inflate(context, R.layout.item_viewpager, null);
RoundImageView itemImage = (RoundImageView) view.findViewById(R.id.item_image);
itemImage.setImageResource(resIds[position]);
container.addView(view);
return view;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
}
}
ViewPager的setPageTransformer是用來控制view的切換動畫的
looviewpager.setPageTransformer(true, new ViewPager.PageTransformer() {
float scale = 0.9f;
@Override
public void transformPage(View page, float position) {
if (position >= 0 && position <= 1) {
page.setScaleY(scale + (1 - scale) * (1 - position));
} else if (position > -1 && position < 0) {
page.setScaleY(1 + (1 - scale) * position);
} else {
page.setScaleY(scale);
}
}
});