自定義組合控制元件:Banner、輪播圖、廣告欄控制元件
阿新 • • 發佈:2018-12-22
1. 專案概述
這裡,我們使用自定義組合控制元件實現一個自動輪播的廣告條,也叫輪播圖,完整版的效果圖如下圖所示。其實,這就是我們經常見到的滾動廣告,預設情況下每隔N 秒會自動滾動,用手指左右滑動時也會切換到上一張或者下一張。當介面切換時,對應廣告圖片的標題也會隨著改變,並且還有對應圖片索引的點也會被選中變為紅色。此處,實現的核心控制元件是ViewPager,它是Android3.0 版本加入的新控制元件,為了向下相容,谷歌給我們提供了android-support-v4.jar 包。
2. 輪播圖UI佈局
佈局整體採用RelativeLayout,android.support.v4.view.ViewPager,TextView,LinearLayout 配合使用佈局檔案activity_main.xml 的程式碼如下檔案所示:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v4.view.ViewPager
android:id="@+id/vp_pager"
android:layout_width="match_parent"
android:layout_height="160dp"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:background ="#a000"
android:orientation="vertical"
android:padding="5dp">
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="新聞標題"
android:textColor="#fff"
android:textSize="16sp"/>
<LinearLayout
android:id="@+id/ll_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:orientation="horizontal">
</LinearLayout>
</LinearLayout>
</FrameLayout>
</RelativeLayout>
3. 輪播圖的程式碼邏輯實現
<?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="wrap_content"
android:orientation="vertical">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v4.view.ViewPager
android:id="@id/viewpager"
android:layout_width="match_parent"
android:layout_height="180dp"/>
<!--android:background="#a000"-->
<LinearLayout
android:id="@id/content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:orientation="vertical"
android:padding="5dp">
<TextView
android:id="@id/tvTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:textColor="#fff"
android:textSize="16sp"/>
<LinearLayout
android:id="@id/llcontainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="3dp"
android:gravity="center_horizontal"
android:orientation="horizontal"/>
</LinearLayout>
</FrameLayout>
<android.support.v7.widget.RecyclerView
android:id="@id/recyclerview"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
public class BannerActivity extends AppCompatActivity implements ViewPager.OnPageChangeListener{
@Bind(R.id.viewpager)
public ViewPager mViewPager;
@Bind(R.id.tvTitle)
public TextView mTextView;
@Bind(R.id.llcontainer)
public LinearLayout mContainer;
@Bind(R.id.content)
public LinearLayout mContent;
@Bind(R.id.recyclerview)
RecyclerView mRecyclerView;
private int mPreviousPos;
private int[] imgs = new int[]{R.mipmap.a, R.mipmap.b, R.mipmap.c, R.mipmap.d, R.mipmap.e};
private String[] title;
private ArrayList<String> transformerList = new ArrayList<>();
private RvAdapter mRvAdapter;
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
int currentItem = mViewPager.getCurrentItem();
mViewPager.setCurrentItem(++currentItem);
mHandler.sendEmptyMessageDelayed(0, 5000);
}
};
private ViewPagerScroller mScroller;
private ViewPagerScroller scroller;
private ActionBar mActionBar;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initView();
initRecyclerView();
initListener();
initTransformer();
initViewPagerScroll();
}
private void initView() {
setContentView(R.layout.activity_banner);
ButterKnife.bind(this);
title = UIUtil.getStringArray(R.array.title);
SpannableString actionBarTitle = new SpannableString("大圖輪播");
actionBarTitle.setSpan(new ForegroundColorSpan(Color.WHITE), 0, actionBarTitle.length(),
Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
mActionBar = getSupportActionBar();
mActionBar.setTitle(actionBarTitle);
mViewPager.setAdapter(new Adapter());
int middle = Integer.MAX_VALUE / 2;
int extra = middle % imgs.length;
int currentItem = middle - extra;
mViewPager.setCurrentItem(currentItem);
mHandler.sendEmptyMessageDelayed(0, 5000);
for (int i = 0; i < imgs.length; i++) {
ImageView img = new ImageView(this);
img.setImageResource(R.drawable.point_selector);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout
.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
if (i != 0) {
params.leftMargin = 10;
img.setEnabled(false);
}
img.setLayoutParams(params);
mContainer.addView(img);
}
mTextView.setText(title[0]);
mViewPager.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver
.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
BannerActivity.this.onPageSelected(0);
mViewPager.getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
});
}
private void initRecyclerView() {
LinearLayoutManager manager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(manager);
mRvAdapter = new RvAdapter(this, R.layout.list_item, transformerList);
mRecyclerView.setAdapter(mRvAdapter);
}
private void initListener() {
mViewPager.addOnPageChangeListener(this);
/*new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int
positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
int pos = position % imgs.length;
mTextView.setText(title[pos]);
mContainer.getChildAt(pos).setEnabled(true);
mContainer.getChildAt(mPreviousPos).setEnabled(false);
mPreviousPos = pos;
colorChange(pos);
}
@Override
public void onPageScrollStateChanged(int state) {
}
}*/
mViewPager.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mHandler.removeCallbacksAndMessages(null);
break;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
mHandler.sendEmptyMessageDelayed(0, 5000);
break;
}
return false;
}
});
mRvAdapter.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(ViewGroup parent, View view, Object o, int position) {
String transforemerName = transformerList.get(position);
try {
Class clazz = Class.forName("com.ToxicBakery.viewpager.transforms." +
transforemerName);
ABaseTransformer transformer = (ABaseTransformer) clazz.newInstance();
mViewPager.setPageTransformer(true, transformer);
if (transforemerName.equals("StackTransformer")) {
scroller.setScrollDuration(1200);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
@Override
public boolean onItemLongClick(ViewGroup parent, View view, Object o, int position) {
return false;
}
});
}
/**
* 設定ViewPager的滑動速度
*/
private void initViewPagerScroll() {
Field mScroller = null;
try {
mScroller = ViewPager.class.getDeclaredField("mScroller");
mScroller.setAccessible(true);
scroller = new ViewPagerScroller(mViewPager.getContext());
mScroller.set(mViewPager, scroller);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
private void initTransformer() {
//各種翻頁效果
transformerList.add(DefaultTransformer.class.getSimpleName());
transformerList.add(AccordionTransformer.class.getSimpleName());
transformerList.add(BackgroundToForegroundTransformer.class.getSimpleName());
transformerList.add(CubeInTransformer.class.getSimpleName());
transformerList.add(CubeOutTransformer.class.getSimpleName());
transformerList.add(DepthPageTransformer.class.getSimpleName());
transformerList.add(FlipHorizontalTransformer.class.getSimpleName());
transformerList.add(FlipVerticalTransformer.class.getSimpleName());
transformerList.add(ForegroundToBackgroundTransformer.class.getSimpleName());
transformerList.add(RotateDownTransformer.class.getSimpleName());
transformerList.add(RotateUpTransformer.class.getSimpleName());
transformerList.add(StackTransformer.class.getSimpleName());
transformerList.add(ZoomInTransformer.class.getSimpleName());
transformerList.add(ZoomOutTranformer.class.getSimpleName());
mRvAdapter.notifyDataSetChanged();
}
private void colorChange(int pos) {
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), imgs[pos]);
Palette.from(bitmap).generate(new Palette.PaletteAsyncListener() {
@Override
public void onGenerated(Palette palette) {
Palette.Swatch vibrant = palette.getVibrantSwatch();
mContent.setBackgroundColor(toARGB(vibrant.getRgb()));
mTextView.setTextColor(vibrant.getBodyTextColor());
mActionBar.setBackgroundDrawable(new ColorDrawable(vibrant.getRgb()));
if (Build.VERSION.SDK_INT >=21){
Window window = getWindow();
window.setStatusBarColor(colorBurn(vibrant.getRgb()));
//window.setNavigationBarColor(Color.RED);
}
}
});
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
int pos = position % imgs.length;
mTextView.setText(title[pos]);
mContainer.getChildAt(pos).setEnabled(true);
if (pos != mPreviousPos){
mContainer.getChildAt(mPreviousPos).setEnabled(false);
}
mPreviousPos = pos;
colorChange(pos);
}
/**
* 顏色新增透明度
* @param rgb
* @return
*/
protected static int toARGB(int rgb){
int red = rgb >> 16 & 0xFF;
int green = rgb >> 8 & 0xFF;
int blue = rgb & 0xFF;
return Color.argb(180 , red , green , blue );
}
/**
* 顏色加深處理
* @param RGBValues
* @return
*/
private int colorBurn(int RGBValues) {
int alpha = RGBValues >> 24;
int red = RGBValues >> 16 & 0xFF;
int green = RGBValues >> 8 & 0xFF;
int blue = RGBValues & 0xFF;
red = (int) Math.floor(red * (1 - 0.1));
green = (int) Math.floor(green * (1 - 0.1));
blue = (int) Math.floor(blue * (1 - 0.1));
return Color.rgb(red, green, blue);
}
@Override
public void onPageScrollStateChanged(int state) {
}
private class Adapter extends PagerAdapter {
@Override
public int getCount() {
if (imgs.length != 0) {
return Integer.MAX_VALUE;
}
return 0;
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
int pos = position % imgs.length;
ImageView img = new ImageView(BannerActivity.this);
img.setBackgroundResource(imgs[pos]);
container.addView(img);
return img;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
}
private class RvAdapter extends CommonAdapter<String> {
public RvAdapter(Context context, int layoutId, List<String> datas) {
super(context, layoutId, datas);
}
@Override
public void convert(ViewHolder holder, String s) {
holder.setText(R.id.tv_item, s);
}
}
}
4. 把Banner封裝成一個模組
public class RollViewPager extends ViewPager implements ViewPager.OnPageChangeListener {
private List<String> mImageLists;
private List<String> mTitleLists;
private List<View> mDotLists;
public Context mContext;
private TextView mTopNewsTitle;
private Task mTask;
private boolean hasAdapter = false;
private int oldPosition = 0;
private int mCurrentItem = 0;
private int downX;
private int downY;
private long downTimeMillis;
// 是否滑動
private boolean isMove = false;
public RollViewPager(Context context, List<View> mDotLists) {
super(context);
this.mDotLists = mDotLists;
this.mContext = context;
mTask = new Task();
// 設定viewpager 的觸控事件
RollViewPager.this.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
// 當手指觸控到螢幕的時候。viewpage 停止跳動
// 當手指離開螢幕的時候。viewpage 繼續跳動
if (event.getAction() == MotionEvent.ACTION_DOWN) {
// 獲取到down 的時間
downTimeMillis = System.currentTimeMillis();
// 停止跳動
// 刪除訊息
handler.removeCallbacksAndMessages(null);
// 刪除任務
//handler.removeCallbacks(mTask);
} else if (event.getAction() == MotionEvent.ACTION_UP) {
// 獲取的是當前時間
long currentTimeMillis = System.currentTimeMillis();
if (currentTimeMillis - downTimeMillis < 500) {
// Toast.makeText(mContext, "我被點選了", 0).show();
if (mViewPageOnTouchListener != null) {
mViewPageOnTouchListener.onViewPageClickListener();
}
}
// 繼續跳動
start();
} else if (event.getAction() == MotionEvent.ACTION_CANCEL) {
System.out.println("MotionEvent.ACTION_CANCEL");
start();
}
return false;
}
});
}
public void start() {
if (!hasAdapter) {
hasAdapter = true;
RollViewPagerAdapter adapter = new RollViewPagerAdapter();
RollViewPager.this.setAdapter(adapter);
RollViewPager.this.setOnPageChangeListener(this);
}
handler.postDelayed(mTask, 2000);
}
public void stop() {
handler.removeCallbacksAndMessages(null);
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
super.onPageScrolled(position, positionOffset, positionOffsetPixels);
}
@Override
public void onPageSelected(int position) {
mCurrentItem = position;
if (null != mTitleLists && mTitleLists.size() > 0
&& null != mTopNewsTitle) {
mTopNewsTitle.setText(mTitleLists.get(position));
}
if (null != mDotLists && mDotLists.size() > 0) {
mDotLists.get(position).setBackgroundResource(R.drawable.dot_focus);
mDotLists.get(oldPosition).setBackgroundResource(
R.drawable.dot_normal);
}
oldPosition = position;
}
@Override
public void onPageScrollStateChanged(int state) {
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
downX = (int) ev.getX();
downY = (int) ev.getY();
// isMove = false;
break;
case MotionEvent.ACTION_MOVE:
int currentX = (int) ev.getX();
int currentY = (int) ev.getY();
if (Math.abs(currentX - downX) > Math.abs(currentY - downY)) {
// 左右滑動viewPage
isMove = false;
} else {
// 上下滑動listview
isMove = true;
}
break;
}
// 請求父類不要攔截我
getParent().requestDisallowInterceptTouchEvent(!isMove);
return super.dispatchTouchEvent(ev);
}
private class RollViewPagerAdapter extends PagerAdapter {
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
View view = View.inflate(mContext, R.layout.viewpager_item, null);
ImageView image = (ImageView) view.findViewById(R.id.image);
BitmapUtils.display(mContext, image, mImageLists.get(position));
container.addView(view);
return view;
}
@Override
public int getCount() {
return mImageLists.size();
}
@Override
public boolean isViewFromObject(View arg0, Object arg1) {
return arg0 == arg1;
}
}
/**
* 設定輪播圖上面的標題
*
* @param mTopNewsTitle
* @param mTitleLists
*/
public void setTextTitle(TextView mTopNewsTitle, List<String> mTitleLists) {
if (null != mTopNewsTitle && null != mTitleLists && mTitleLists.size() > 0) {
this.mTopNewsTitle = mTopNewsTitle;
this.mTitleLists = mTitleLists;
mTopNewsTitle.setText(mTitleLists.get(0));
}
}
/**
* 設定背景圖片
*
* @param mImageLists
*/
public void setImageRes(List<String> mImageLists) {
this.mImageLists = mImageLists;
}
private class Task implements Runnable {
@Override
public void run() {
mCurrentItem = (mCurrentItem + 1) % mImageLists.size();
handler.obtainMessage().sendToTarget();
}
}
private Handler handler = new Handler() {
public void handleMessage(android.os.Message msg) {
RollViewPager.this.setCurrentItem(mCurrentItem, false);
start();
}
};
private ViewPageOnTouchListener mViewPageOnTouchListener;
public interface ViewPageOnTouchListener {
public void onViewPageClickListener();
}
public void setViewPageOnTouchListener(ViewPageOnTouchListener viewPageOnTouchListener) {
mViewPageOnTouchListener = viewPageOnTouchListener;
}
}
5. 開源專案
關於我
License
Copyright 2015 AllenIverson
Copyright 2012 Jake Wharton
Copyright 2011 Patrik Åkerfeldt
Copyright 2011 Francisco Figueiredo Jr.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.