Android Studio - 第四十六期 不會AAR的輪播寫法
阿新 • • 發佈:2017-08-02
android banner
最近在學習擼擼的代碼,發現他的輪播寫法很獨特,但是有bug,就重新修改了一下,現在支持左右點擊和圓點自定義。
BannerAdapter:(註意適配器自己看ImageView和onclick的自己項目的寫法~)
package com.example.p029_banner_lunbo.adapter; import android.app.Activity; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import com.example.p029_banner_lunbo.bannerutils.BannerView; import com.example.p029_banner_lunbo.domain.Biaoge_listBean; import java.util.List; public class BannerAdapter extends BannerView.Adapter { private List<Biaoge_listBean> mAdList; private Object mReceiver; public BannerAdapter(Object receiver, List<Biaoge_listBean> items) { mReceiver = receiver; mAdList = items; } @Override public int getRealCount() { return mAdList.size(); } @Override public Object instantiateItem(final ViewGroup container, int position) { int size = mAdList.size(); if (size == 0) { return null; } final int pos = position % size; final Biaoge_listBean item = mAdList.get(pos); ViewGroup.LayoutParams p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); ImageView iv = new ImageView(container.getContext()); iv.setScaleType(ImageView.ScaleType.FIT_XY); iv.setAdjustViewBounds(true); container.addView(iv, p); iv.setBackgroundResource(item.getImg_url()); // GlideUtil.display(container.getContext(), iv, item.getPic_url(), // GlideOptionsFactory.get(GlideOptionsFactory.Type.RADIUS)); iv.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // MobEventHelper.onEvent(container.getContext(), "UI2_ec_index_banner"); // MobEventHelper.onEvent(container.getContext(), "UI2_ec_index_banner_" + String.valueOf(pos + 1)); if (container.getContext() instanceof Activity) { Activity act = (Activity) container.getContext(); //跳轉bufen // HiosHelper.resolveAd(act, mReceiver, item.getUrl()); } } }); return iv; } @Override public void destroyItem(ViewGroup container, int position, Object object) { container.removeView((View) object); } }
DotIndicatorView:(圓點的方法大部分都public了,大家可以DotIndicatorView.自定義~)
package com.example.p029_banner_lunbo.bannerutils; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.TypedValue; import android.view.View; /** * 圓點導航 * @author geek * */ public class DotIndicatorView extends View { private Paint mPaint; private int mPadding; private int mCircleRadius; private int mCurrentColor; private int mNormalColor; private int mCount = 3; private int mCurrent; public DotIndicatorView(Context context) { super(context); initView(); } public DotIndicatorView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public DotIndicatorView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); initView(); } private void initView() { DisplayMetrics dm = getResources().getDisplayMetrics(); mPadding = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, dm); mCircleRadius = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 4, dm); mCurrentColor = Color.WHITE; mNormalColor = Color.argb(88, 91, 91, 91); mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int width = mCircleRadius * 2 * mCount + mPadding * (mCount -1); int height = mCircleRadius * 2; setMeasuredDimension(width, height); } @Override protected void onDraw(Canvas canvas) { for (int i = 0; i < mCount; i++) { canvas.save(); canvas.translate((mCircleRadius * 2 + mPadding) * i, 0); if(i == mCurrent) mPaint.setColor(mCurrentColor); else mPaint.setColor(mNormalColor); canvas.drawCircle(mCircleRadius , mCircleRadius, mCircleRadius, mPaint); canvas.restore(); } } /** * 創建導航 * @param count 個數 */ public void create(int count) { mCount = count; requestLayout(); invalidate(); } /** * 選中當前 * @param position 選中位置 */ public void current(int position) { mCurrent = position; invalidate(); } /** * 獲取當前選中的位置 * @return */ public int current() { return mCurrent; } }
BannerView:(自定義的View~)
package com.example.p029_banner_lunbo.bannerutils; import android.content.Context; import android.content.res.TypedArray; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.os.Parcelable; import android.support.v4.view.PagerAdapter; import android.support.v4.view.ViewPager; import android.support.v4.view.ViewPager.OnPageChangeListener; import android.util.AttributeSet; import android.view.Gravity; import android.view.MotionEvent; import android.view.View; import android.widget.FrameLayout; import com.example.p029_banner_lunbo.R; import java.lang.ref.WeakReference; public class BannerView extends FrameLayout { private static final int MSG_RUN = 1; private ViewPager mViewPager; /** * 導航的小點 */ private DotIndicatorView mIndicator; private Adapter mAdapter; /** * 是否處於滑動的狀態 */ private boolean isScrolling; private int mIndicatorPosition; // center_hori left /** * 是否顯示indicator */ private boolean isShowIndicator = true; private boolean isTouch; private Handler mHandler; private BannerViewHelper mHelper; private int mScrollTime; public BannerView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public BannerView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.BannerView, defStyle, 0); mIndicatorPosition = ta.getInt(R.styleable.BannerView_indicator_position, 0); isShowIndicator = ta.getBoolean(R.styleable.BannerView_indicator_visible, true); mScrollTime = ta.getInteger(R.styleable.BannerView_scroll_time, 3000); isScrolling = ta.getBoolean(R.styleable.BannerView_auto_start, false); ta.recycle(); initView(context); } private void initView(Context context) { mViewPager = new ViewPager(context); mViewPager.addOnPageChangeListener(mOnPageChangeListener); addView(mViewPager);//, viewPagerParams); mHandler = new H(mViewPager); mIndicator = new DotIndicatorView(context); LayoutParams indicatorParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); if (mIndicatorPosition == 0) { indicatorParams.gravity = Gravity.BOTTOM | Gravity.LEFT; } else if (mIndicatorPosition == 1) { indicatorParams.gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL; } else if (mIndicatorPosition == 2) { indicatorParams.gravity = Gravity.BOTTOM | Gravity.RIGHT; } indicatorParams.bottomMargin = 20; if (!isShowIndicator) { return; } addView(mIndicator, indicatorParams); } @Override protected void onAttachedToWindow() { if (isScrolling) { startScroll(); } super.onAttachedToWindow(); mHelper = new BannerViewHelper(this); } @Override public boolean dispatchTouchEvent(MotionEvent ev) { if (mHelper != null) { mHelper.resolveTouchConflict(ev); } return super.dispatchTouchEvent(ev); } @Override protected LayoutParams generateDefaultLayoutParams() { return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); } @Override public LayoutParams generateLayoutParams(AttributeSet attrs) { return new LayoutParams(getContext(), attrs); } @Override protected android.view.ViewGroup.LayoutParams generateLayoutParams( android.view.ViewGroup.LayoutParams p) { return new LayoutParams(p); } @Override protected boolean checkLayoutParams(android.view.ViewGroup.LayoutParams p) { return p instanceof LayoutParams; } private OnPageChangeListener mOnPageChangeListener = new OnPageChangeListener() { @Override public void onPageSelected(int position) { int relCount = mAdapter.getRealCount(); if (relCount <= 0) { mIndicator.current(0); } else { mIndicator.current(position % relCount); } } @Override public void onPageScrolled(int arg0, float arg1, int arg2) { } @Override public void onPageScrollStateChanged(int arg0) { isTouch = arg0 == ViewPager.SCROLL_STATE_DRAGGING; if (arg0 == ViewPager.SCROLL_STATE_IDLE && isScrolling) { mHandler.removeMessages(MSG_RUN); Message msg = mHandler.obtainMessage(MSG_RUN, isScrolling ? 1 : 0, isTouch ? 1 : 0); mHandler.sendMessageDelayed(msg, mScrollTime); } } }; /** * 開始自動滾動 */ public void startScroll() { mHandler.removeMessages(MSG_RUN); isScrolling = true; Message msg = mHandler.obtainMessage(MSG_RUN, 1, isTouch ? 1 : 0); mHandler.sendMessageDelayed(msg, mScrollTime); } /** * 停止自動滾動 */ public void stopScroll() { isScrolling = false; if (mHandler != null) { mHandler.removeMessages(MSG_RUN); } } @Override protected Parcelable onSaveInstanceState() { Bundle bundle = new Bundle(); bundle.putBoolean("scroll", isScrolling); bundle.putParcelable("state", super.onSaveInstanceState()); return bundle; } @Override protected void onRestoreInstanceState(Parcelable state) { Bundle bundle = (Bundle) state; isScrolling = bundle.getBoolean("scroll"); state = bundle.getParcelable("state"); if (state != null) { super.onRestoreInstanceState(state); } } // @Override // protected void onAttachedToWindow() { // super.onAttachedToWindow(); // if(isScrolling) mHandler.sendEmptyMessage(MSG_RUN); // } @Override protected void onDetachedFromWindow() { mHandler.removeMessages(MSG_RUN); super.onDetachedFromWindow(); } /** * 設置banner的數據集合 */ public void setAdapter(Adapter adapter) { mAdapter = adapter; mViewPager.setAdapter(adapter); mIndicator.create(adapter.getRealCount()); } /** * 獲取adapter */ public Adapter getAdapter() { return mAdapter; } public int getCurrent() { return mViewPager.getCurrentItem() + 1; } public void setCurrent(int current) { mViewPager.setCurrentItem(current); } private static class H extends Handler { private WeakReference<ViewPager> mViewPager; public H(ViewPager pager) { mViewPager = new WeakReference<>(pager); } public void handleMessage(Message msg) { if (mViewPager.get() == null) return; boolean isScrolling = msg.arg1 == 1; boolean isTouch = msg.arg2 == 1; if (msg.what == MSG_RUN && isScrolling) { if (!isTouch) { int pos = mViewPager.get().getCurrentItem() + 1; mViewPager.get().setCurrentItem(pos); // sendEmptyMessageDelayed(MSG_RUN, 3000); } else { removeMessages(MSG_RUN); } } } } public static abstract class Adapter extends PagerAdapter { @Override public final int getCount() { return Integer.MAX_VALUE; } /** * 獲取真實的數據統計 * * @return */ public abstract int getRealCount(); @Override public final boolean isViewFromObject(View arg0, Object arg1) { return arg0 == arg1; } public Object getItem(int position) { return position; } } }
BannerViewHelper:(用於解決BannerView和SwipeRefreshLayout的沖突)
package com.example.p029_banner_lunbo.bannerutils; import android.support.v4.widget.SwipeRefreshLayout; import android.view.MotionEvent; import android.view.VelocityTracker; import android.view.ViewGroup; /** * 用於解決BannerView和SwipeRefreshLayout的沖突 * @author geek * */ public class BannerViewHelper { private BannerView mBannerView; private SwipeRefreshLayout mSwipeRefreshLayout; private VelocityTracker mVelocityTracker; private float mAccuracy = 1.f; public BannerViewHelper(BannerView bannerView) { mBannerView = bannerView; mSwipeRefreshLayout = findSwipeRefreshLayout(); } public BannerViewHelper(BannerView bannerView, float accuracy) { this(bannerView); mAccuracy = accuracy; } public void resolveTouchConflict(MotionEvent event) { if(mSwipeRefreshLayout == null) return; setupVelocityTracker(event); switch (event.getAction()) { case MotionEvent.ACTION_MOVE: if(!mSwipeRefreshLayout.isEnabled()) return; mVelocityTracker.computeCurrentVelocity(1000); if(Math.abs(mVelocityTracker.getXVelocity()) > Math.abs(mVelocityTracker.getYVelocity()) * mAccuracy) { mSwipeRefreshLayout.setEnabled(false); } break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: mSwipeRefreshLayout.setEnabled(true); recycleVelocityTracker(); default: break; } } private void setupVelocityTracker(MotionEvent event) { if(mVelocityTracker == null) mVelocityTracker = VelocityTracker.obtain(); mVelocityTracker.addMovement(event); } private void recycleVelocityTracker() { if(mVelocityTracker != null) { mVelocityTracker.clear(); mVelocityTracker.recycle(); mVelocityTracker = null; } } private SwipeRefreshLayout findSwipeRefreshLayout() { ViewGroup parent = (ViewGroup) mBannerView.getParent(); while(parent != null && parent.getId() != android.R.id.content) { if(parent instanceof SwipeRefreshLayout) return (SwipeRefreshLayout) parent; parent = (ViewGroup) parent.getParent(); } return null; } }
xml布局:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#ccc" android:orientation="vertical"> <com.example.p029_banner_lunbo.bannerutils.BannerView android:id="@+id/banner" android:layout_width="match_parent" android:layout_height="400dp" app:indicator_position="center" app:indicator_visible="false" app:scroll_time="8000" /> </LinearLayout> <TextView android:id="@+id/tv_left" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/icon_left" /> <TextView android:id="@+id/tv_right" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:background="@drawable/icon_right" /> </RelativeLayout>
調用方法:
tv_left = (TextView) findViewById(R.id.tv_left); tv_left.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //左← ToastUtil.showToastShort(MainActivity.this, "左"); mBannerView.setCurrent(mBannerView.getCurrent() - 2); } }); tv_right = (TextView) findViewById(R.id.tv_right); tv_right.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //右→ ToastUtil.showToastShort(MainActivity.this, "右"); mBannerView.setCurrent(mBannerView.getCurrent()); } }); mBannerView = (BannerView) findViewById(R.id.banner); Data1(); mBannerView.setAdapter(new BannerAdapter(this, mList1)); mBannerView.stopScroll(); mBannerView.startScroll();
代碼已經整理好,效果如下圖:
圖1:
圖2:
地址:https://github.com/geeklx/MyApplication/tree/master/p029_banner_lunbo
附:
本文出自 “梁肖技術中心” 博客,請務必保留此出處http://liangxiao.blog.51cto.com/3626612/1953066
Android Studio - 第四十六期 不會AAR的輪播寫法