最近看到公司項(xiàng)目用的是一個(gè)webView實(shí)現(xiàn)的Banner寨昙,個(gè)人覺(jué)得用戶體驗(yàn)不怎么好,第一:用戶點(diǎn)擊banner圖還可以輕微的上下滑動(dòng)(難適配的原因)老翘;第二:用戶息屏之后再打開(kāi)芹啥,webView會(huì)閃一下,這個(gè)原因還沒(méi)找到铺峭,知道的同學(xué)可以指教一下墓怀。這肯定不能忍,對(duì)不對(duì)卫键!網(wǎng)上也有很多這方面的文章了吧傀履,但那究竟是別人的,自己寫(xiě)的應(yīng)該會(huì)更爽一些吧莉炉。
首先钓账,分析下需求:
- 幾張圖片過(guò)一段時(shí)間就切換一次;
- 當(dāng)觸摸圖片絮宁,圖片暫停切換梆暮;
大概思路大家都想到用ViewPager去實(shí)現(xiàn) --> ok,需求分析完畢绍昂。下面先編寫(xiě)XML:
<pre>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="200dp"
tools:context="test.nicely.com.application.MainActivity">
<android.support.v4.view.ViewPager
android:id="@+id/view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent">
</android.support.v4.view.ViewPager>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:background="#55000000"
android:padding="5dp">
<TextView
android:id="@+id/tv_img_desc"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:text="banner"
android:textColor="#ffffff"
android:textSize="16sp"/>
// 小圓點(diǎn)的容器,用來(lái)動(dòng)態(tài)添加
<LinearLayout
android:layout_centerVertical="true"
android:id="@+id/dot_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_marginRight="8dp"
android:orientation="horizontal">
</LinearLayout>
</RelativeLayout>
</RelativeLayout>
</pre>
直接貼代碼吧 ,畢竟Talk is cheap ,接下看MainActivity類(lèi)的代碼邏輯處理:
public class MainActivity extends AppCompatActivity implements ViewPager.OnPageChangeListener,
View.OnTouchListener {
private String[] arrUrl = {AppConstant.baseUrl + "teacher_1.png",
AppConstant.baseUrl + "teacher_2.png",
AppConstant.baseUrl + "teacher_3.png"};
// mock banner Title
private int[] resTxt = {R.string.title_1, R.string.title_2, R.string.title_3};
private ViewPager mViewPager;
private LinearLayout mDot_container;
private MyPagerAdapter mAdapter;
private TextView mTvImgDesc;
private int mPrePosition;
//private AutoCycleTask mAutoCycleTask;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 設(shè)置全透明的狀態(tài)欄
CommonUtils.setTransparentStatus(this);
initView();
performDot();
performViewPager();
}
private void initView() {
mViewPager = (ViewPager) findViewById(R.id.view_pager);
mDot_container = (LinearLayout) findViewById(R.id.dot_container);
mTvImgDesc = (TextView) findViewById(R.id.tv_img_desc);
}
private void performDot() {
for (int i = 0; i < resTxt.length; i++) {
View dotView = new View(this);
dotView.setBackgroundResource(R.drawable.dot);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(15, 15);
// 第一個(gè)原點(diǎn)不設(shè)置左邊距
if (i != 0) {
params.leftMargin = 15;
}
dotView.setEnabled(false);
dotView.setLayoutParams(params);
mDot_container.addView(dotView);
}
}
private void performViewPager() {
if (mAdapter == null) {
mAdapter = new MyPagerAdapter(this, arrUrl);
}
mViewPager.setAdapter(mAdapter);
mViewPager.addOnPageChangeListener(this);
mViewPager.setOnTouchListener(this);
// Integer.MAX_VALUE / 2 有可能是任何item的位置 - 余數(shù)則讓他和集合的pos=0的位置吻合
int item = Integer.MAX_VALUE / 2 - (Integer.MAX_VALUE / 2 % resTxt.length);
mViewPager.setCurrentItem(item);// 設(shè)置初始位置
// 將第一個(gè)圓點(diǎn)設(shè)置選中的顏色
mDot_container.getChildAt(mPrePosition).setEnabled(true);
mTvImgDesc.setText(resTxt[mPrePosition]);
// 實(shí)現(xiàn) 自動(dòng)切換
autoCycle();
}
private void autoCycle() {
if (mAutoCycleTask == null) {
mAutoCycleTask = new AutoCycleTask();
}
mAutoCycleTask.start();
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
Log.d("nicely","position===" + position + "positionOffset===" + positionOffset + "positionOffsetPixels===" + positionOffsetPixels);
}
@Override
public void onPageSelected(int position) {
int newPos = position % mDot_container.getChildCount();
mDot_container.getChildAt(mPrePosition).setEnabled(false);
mDot_container.getChildAt(newPos).setEnabled(true);
mTvImgDesc.setText(resTxt[newPos]);
mPrePosition = newPos;
}
@Override
public void onPageScrollStateChanged(int state) {
}
}
上面的邏輯也比較簡(jiǎn)單,簡(jiǎn)單梳理一下: 動(dòng)態(tài)添加小圓點(diǎn)到線性布局當(dāng)中;監(jiān)聽(tīng)Viewpager選中的item動(dòng)態(tài)切換小圓點(diǎn)的選中位置;再把PagerAdapter的subclass代碼貼上來(lái):
/*
* @項(xiàng)目名: Application
* @包名: test.nicely.com.application
* @文件名: MyPagerAdapter
* @創(chuàng)建者: lz
* @創(chuàng)建時(shí)間: 2017/1
* @描述: TODO
*/
public class MyPagerAdapter extends PagerAdapter {
private static final String TAG = "MyPagerAdapter";
private Context mContext;
private String[] mArrUrl;
public MyPagerAdapter(Context context, String[] arrUrl) {
mContext = context;
mArrUrl = arrUrl;
}
@Override
public int getCount() {
// return arrUrl.lenth;
// 循環(huán)用
return Integer.MAX_VALUE;
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
// position此時(shí)的總大小是Integer.MAX_VALUE,需要轉(zhuǎn)換(position本來(lái)就跟自然數(shù)差1了)
// 循環(huán)用
position = position % mArrUrl.length;
ImageView imageView = new ImageView(mContext);
imageView.setScaleType(ImageView.ScaleType.FIT_XY);
// 使用picasso加載圖片
Picasso.with(mContext).load(mArrUrl[position]).error(R.mipmap.error).into(imageView);
container.addView(imageView);
return imageView;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
}
到此為止,就差我們想要的循環(huán)沒(méi)有實(shí)現(xiàn)了.這里有些同學(xué)可能會(huì)在這里踩坑----> 高能預(yù)警!!!有些同學(xué)在這個(gè)方法里instantiateItem使用的是從外邊傳的View進(jìn)來(lái),這時(shí)候你一切換view ,就會(huì)報(bào)下邊這個(gè)錯(cuò)誤:
This view has a parent...
可能是大家對(duì)Viewpager不熟悉,加上自己的想當(dāng)然所導(dǎo)致的哈,接下來(lái)我們就要實(shí)現(xiàn)動(dòng)態(tài)切換了:實(shí)現(xiàn)這個(gè)定時(shí)器功能.
android中有許多方式,什么Timer ,alarmmanager,Handler等等.
我這里選擇是Handler,ok,老套路,直接貼實(shí)現(xiàn)定時(shí)器邏輯代碼(AutoCycleTask類(lèi)是MainActivity的內(nèi)部類(lèi)),自定義了一個(gè)start()和stop()方法:
class AutoCycleTask extends Handler implements Runnable {
@Override
public void run() {
// 設(shè)置輪播下一圖
int currentItem = mViewPager.getCurrentItem();
mViewPager.setCurrentItem(++currentItem);
postDelayed(this, 2000);
}
public void start() {
postDelayed(this, 2000);
}
public void stop() {
removeCallbacks(this);
}
}
接下來(lái)在界面銷(xiāo)毀時(shí),將handler消息隊(duì)列中的消息移除:
@Override
protected void onDestroy() {
super.onDestroy();
mAutoCycleTask.removeCallbacksAndMessages(null);
mAutoCycleTask = null;
}
最后還差一個(gè)需求點(diǎn)沒(méi)完成
- 當(dāng)觸摸圖片惕蹄,圖片暫停切換.
這不就監(jiān)聽(tīng)Viewpager的觸摸事件就可以搞定了:
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mAutoCycleTask.stop();
break;
case MotionEvent.ACTION_MOVE:
mAutoCycleTask.stop();
break;
case MotionEvent.ACTION_UP:
mAutoCycleTask.start();
break;
}
return false;
}
貼上截圖(簡(jiǎn)書(shū)暫時(shí)不會(huì)搞GIF圖 [尷尬]):