Android 輪播圖從 0 到 1
阿新 • • 發佈:2019-01-10
輪播圖是 Android 常用功能之一,效果大概是這樣的:
之前我封裝寫了一個,基本達到了要求,是繼承了 Fragment(當時腦袋肯定鏽掉了),裡面 Viewpager add Fragment,這次專案多處有輪播圖,發現之前封裝的不夠用,簡直漏洞百出:1、比如底部 point 的位置,之前固定在中間,現在可能要放在右下角,point 最好也能動態改圖片;2、現在專案跟微信一樣,底部 tab 切換,中間是 Fragment 替換,發現輪播圖有問題,Fragment A 迴圈的 point 的 positoin 居然影響到了 Fragment B,照理,這是兩個 BannerFragment,不會影響的啊,報以下錯誤:
java.lang.IllegalStateException: The application's PagerAdapter changed the adapter's
contents without calling PagerAdapter#notifyDataSetChanged!
經過排查,找到了原因,因為 Viewpager add Fragment 我全部放在一個類,因此:
public static List<Object> bannerList = new ArrayList<>();
這裡 static 壞事了,之前一個 banner 沒有暴露出來。3、繼承了 Fragment,引用比較麻煩,Fragment 有兩者引用方法,xml 和程式碼,兩者方式 addData 卻報錯;4、banner 沒有寫點選回撥。
再次封裝
綜合以上問題,我進行了優化,繼承 LinearLayout,當一個控制元件來引用,省去不必要的麻煩,底部 point 的位置可以設定:
pointLayout.setGravity(bannerPointGravity);
另外自定義了屬性,動態設定 point 大小和圖片,輪播圖迴圈時間,也能程式碼設定,完整程式碼示例:
* Created by WuXiaolong on 2017/8/24. * 個人部落格:http://wuxiaolong.me */ public class BannerLayout extends LinearLayout { private ViewPager viewPager; private LinearLayout pointLayout; private ScheduledExecutorService scheduler; private int mPosition = 0; private int mBannerCount = 1; private Context context; private Activity activity; private int bannerPointSize; private int bannerPointGravity; private int bannerPointDrawableSelected, bannerPointDrawableUnselected; private int bannerDelaySecond; public BannerLayout(Context context) { this(context, null); } public BannerLayout(Context context, @Nullable AttributeSet attrs) { this(context, attrs, 0); } public BannerLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initView(context, attrs); } private void initView(Context context, AttributeSet attrs) { this.context = context; activity = (Activity) context; TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.BannerLayout); bannerPointSize = typedArray.getDimensionPixelSize(R.styleable.BannerLayout_bannerPointSize, 10); bannerPointGravity = typedArray.getInt(R.styleable.BannerLayout_bannerPointGravity, Gravity.CENTER); bannerDelaySecond = typedArray.getInt(R.styleable.BannerLayout_bannerDelaySecond, 5); bannerPointDrawableSelected = typedArray.getResourceId(R.styleable.BannerLayout_bannerPointDrawableSelected, R.mipmap.point01); bannerPointDrawableUnselected = typedArray.getResourceId(R.styleable.BannerLayout_bannerPointDrawableUnselected, R.mipmap.point02); typedArray.recycle(); View view = View.inflate(context, R.layout.banner_view_pager, null); addView(view); viewPager = (ViewPager) view.findViewById(R.id.viewPager); pointLayout = (LinearLayout) view.findViewById(R.id.pointLayout); pointLayout.setGravity(bannerPointGravity); viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageSelected(int position) { addPointLayout(position); } @Override public void onPageScrollStateChanged(int state) { } }); } public void start(List<Object> bannerList) { bannerShutdown(); mBannerCount = bannerList.size(); BannerPagerAdapter bannerPagerAdapter = new BannerPagerAdapter(context, bannerList); viewPager.setAdapter(bannerPagerAdapter); addPointLayout(0); startScheduler(); } private void addPointLayout(int position) { pointLayout.removeAllViews(); for (int i = 0; i < mBannerCount; i++) { ImageView imageView = new ImageView(context); LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(bannerPointSize, bannerPointSize); layoutParams.setMargins(10, 0, 0, 0); imageView.setLayoutParams(layoutParams); if (position == i) { imageView.setImageResource(bannerPointDrawableSelected); } else { imageView.setImageResource(bannerPointDrawableUnselected); } pointLayout.addView(imageView); } } private void startScheduler() { scheduler = Executors.newSingleThreadScheduledExecutor(); scheduler.scheduleAtFixedRate(new Runnable() { @Override public void run() { mPosition = viewPager.getCurrentItem(); if (mPosition < mBannerCount - 1) { mPosition++; } else { mPosition = 0; } activity.runOnUiThread(new Runnable() { @Override public void run() { viewPager.setCurrentItem(mPosition); } }); } }, 1, bannerDelaySecond, TimeUnit.SECONDS); } public void bannerShutdown() { if (scheduler != null) scheduler.shutdown(); } private class BannerPagerAdapter extends PagerAdapter { private List<Object> bannerList = new ArrayList<>(); private Context context; BannerPagerAdapter(Context context, List<Object> bannerList) { this.context = context; this.bannerList.clear(); this.bannerList.addAll(bannerList); } @Override public int getCount() { return bannerList.size(); } @Override public boolean isViewFromObject(View view, Object object) { return view == object; } @Override public Object instantiateItem(ViewGroup container, final int position) { ImageView imageView = new ImageView(context); imageView.setScaleType(ImageView.ScaleType.CENTER_CROP); Object object = bannerList.get(position); //這裡我封裝了 Glide 4.0 的工具類,用於顯示圖片 ImageLoaderUtil.load(context, object, imageView); container.addView(imageView); return imageView; } @Override public void destroyItem(ViewGroup container, int position, Object object) { container.removeView((View) object); } } public int dp2px(float var0) { float var1 = context.getResources().getDisplayMetrics().density; return (int) (var0 * var1 + 0.5F); } public void setBannerPointSize(int bannerPointSize) { this.bannerPointSize = dp2px(bannerPointSize); } public void setBannerPointGravity(int bannerPointGravity) { this.bannerPointGravity = bannerPointGravity; pointLayout.setGravity(bannerPointGravity); } public void setBannerPointDrawableSelected(int bannerPointDrawableSelected) { this.bannerPointDrawableSelected = bannerPointDrawableSelected; } public void setBannerPointDrawableUnselected(int bannerPointDrawableUnselected) { this.bannerPointDrawableUnselected = bannerPointDrawableUnselected; } public void setBannerDelaySecond(int bannerDelaySecond) { this.bannerDelaySecond = bannerDelaySecond; } }
其中自定義屬性的attrs.xml:
<resources>
<declare-styleable name="BannerLayout">
<!--輪播圖點的大小-->
<attr name="bannerPointSize" format="dimension" />
<!--輪播圖點的位置,分別有左中右-->
<attr name="bannerPointGravity" format="enum">
<enum name="left" value="3" />
<enum name="center" value="17" />
<enum name="right" value="5" />
</attr>
<!--輪播圖點選中的圖片-->
<attr name="bannerPointDrawableSelected" format="reference" />
<!--輪播圖點未選中的圖片-->
<attr name="bannerPointDrawableUnselected" format="reference" />
<!--輪播圖迴圈時間,單位秒-->
<attr name="bannerDelaySecond" format="integer" />
</declare-styleable>
</resources>
使用說明
xml
<com.wuxiaolong.bannersample.BannerLayout
android:id="@+id/bannerView"
android:layout_width="match_parent"
android:layout_height="198dp"
app:bannerDelaySecond="3"
app:bannerPointDrawableSelected="@drawable/gray_radius"
app:bannerPointDrawableUnselected="@drawable/white_radius"
app:bannerPointGravity="right"
app:bannerPointSize="10dp" />
呼叫:
public class MainActivity extends AppCompatActivity {
private BannerLayout bannerView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bannerView = (BannerLayout) findViewById(R.id.bannerView);
List<Object> bannerList = new ArrayList<>();
bannerList.add(R.mipmap.horizontal_default);
bannerList.add("http://pic1.win4000.com/wallpaper/5/598161750eddb.jpg");
bannerList.add("http://pic1.win4000.com/wallpaper/4/597efb5b6aae8.jpg");
bannerView.setBannerPointSize(10);
bannerView.setBannerPointGravity(Gravity.CENTER);
bannerView.setBannerPointDrawableSelected(R.drawable.gray_radius);
bannerView.setBannerPointDrawableUnselected(R.mipmap.point01);
bannerView.setBannerDelaySecond(5);
//banner 設定方法完畢時最後呼叫 start 方法
bannerView.start(bannerList);
}
@Override
protected void onStop() {
super.onStop();
bannerView.bannerShutdown();
}
}
最後
歡迎加入Android進階交流群;701740775。進群可免費領取一份最新技術大綱和Android進階資料。請備註csdn