Android使用viewpager实现图片轮播效果
生活随笔
收集整理的這篇文章主要介紹了
Android使用viewpager实现图片轮播效果
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
自定義View實現圖片輪播,實現了圖片自動輪播,手動滑動,輪播標題,以及點擊事件。
里面有很多注釋
一、文件布局
?
二、代碼
ImageBannerViewGroup類
/*** Created by hp on 2018/7/31.* 這是實現圖片輪播的核心類*/public class ImageBannerViewGroup extends ViewGroup {private int children;//我們ViewGroup子視圖的總個數private int childwidth;//子視圖的寬度private int childheight;//子視圖的高度private int x;//此時的x的值 代表的是第一次按下的位置橫坐標、每一次移動過程中一定之前的位置橫坐標private int index = 0;//代表的是我們每張圖片的索引private Scroller scroller;//.利用 Scroller 對象 完成輪播圖的手動輪播/*** 要實現圖片的單擊事件的獲取* 我們 利用一個單擊變量開關進行判斷,在用戶離開屏幕的一瞬間* 我們用判斷變量開關來判斷用戶的操作是點擊還是移動*/private boolean isClick;//true代表的是點擊事件,false代表的是不是點擊事件private ImageBarnnerLister lister;public ImageBarnnerLister getLister(){return lister;}public void setLister(ImageBarnnerLister lister) {this.lister = lister;}public interface ImageBarnnerLister{void clickImageIndex(int pos);//pos代表的是我們當前圖片的具體索引值}private ImageBarnnerViewGroupLisnner barnnerViewGroupLisnner;public ImageBarnnerViewGroupLisnner getBarnnerViewGroupLisnner() {return barnnerViewGroupLisnner;}public void setBarnnerViewGroupLisnner(ImageBarnnerViewGroupLisnner barnnerViewGroupLisnner) {this.barnnerViewGroupLisnner = barnnerViewGroupLisnner;}/*** 實現圖片輪播底部圓點以及底部圓點切換功能步驟思路:* 1.自定義一個集成自FrameLayout的布局,利用FrameLayout布局的特性(在同一位置放置不同的iew最終顯示的是最后一個view)* 利用這個特性我們就可以實現底部圓點的布局* 2.我們需要準備素材,就是底部圓點的素材,我們可以利用Drawable的功能,去實現一個圓點的展示* 3.我們需要繼承FrameLayout來定義一個類,在該類的實現過程中,我們去加載我們剛才自定義的ImageBannerViewGroup核心類* 和我們需要實現的底部圓點的布局LinearLayout來實現*///---自動輪播private boolean isAuto = true;//默認開啟自動輪播private Timer timer = new Timer();private TimerTask task;private Handler autoHandler = new Handler(){@Overridepublic void handleMessage(Message msg) {switch (msg.what){case 0://此時我們需要圖片的自動輪播if(++index >= children){//如果滑到了最后一張圖片就會從第一張從新開始index = 0;}scrollTo(childwidth *index,0);barnnerViewGroupLisnner.selectImage(index);break;}}};private void startAuto(){isAuto = true;}private void stopAuto(){isAuto = false;}/*** 采用Timer,TimerTask,Handler三者相結合的方法實現自動輪播* 抽取兩個方法來控制,是否啟動自動輪播,稱之為 startAuto(),stopAuto();* 我們在2個方法的控制過程中,我們希望能有控制自動開啟輪播圖的開關* 我們需要一個變量參數來作為我們自動啟動輪播圖的開關,為 isAuto boolean true代表開啟,false代表關閉*/public ImageBannerViewGroup(Context context) {super(context);initObj();//.利用 Scroller 對象 完成輪播圖的手動輪播需要用到這個方法,利用 scrollTo、scrollBy 完成輪播圖的手動輪播時可以刪掉}public ImageBannerViewGroup(Context context, AttributeSet attrs) {super(context, attrs);initObj();}public ImageBannerViewGroup(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);initObj();}private void initObj() {scroller = new Scroller(getContext());task = new TimerTask() {@Overridepublic void run() {if(isAuto) {//開啟輪播圖autoHandler.sendEmptyMessage(0);}}};timer.schedule(task,100,3000);}@Overridepublic void computeScroll() {//利用 Scroller 對象 完成輪播圖的手動輪播需要用到這個方法super.computeScroll();if(scroller.computeScrollOffset()){scrollTo(scroller.getCurrX(),0);invalidate();}}/*** 我們在自定義的ViewGroop中,我們必須要實現的方法有:測量-》布局-》繪制* 那么對于來說就是:onMeasure()* 我們對于繪制來說,因為我們是自定義的ViewGroup容器,針對于容器的繪制* 其實就是容器內的子控件的繪制過程,那么我們只需要調用系統自帶的繪制即可,* 也就是對于ViewGroup繪制過程我們不需要再重寫該方法* 調用系統的即可*/@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);/*** 由于我們要實現ViewGroup的容器,* 那么我們就需要知道該容器內的所有子視圖* 我們要想測量我們的ViewGroup的寬度和高度,那么我們就必須先要去測量子視圖* 的寬度和高度之和,才能知道我們的ViewGroup的寬度和高度是多少*///1.求子視圖的個數children = getChildCount();//我們就可以知道子視圖的個數if(0 == children){setMeasuredDimension(0,0);}else{//2.測量子視圖的高度measureChildren(widthMeasureSpec,heightMeasureSpec);//此時我們以第一個子視圖為基準,也就是說我們的viewGroup的高度就是我們第一個子視圖的高度//寬度就是我們第一個姿勢圖的額寬度*子視圖的個數View view = getChildAt(0);//因為此時第一個視圖絕對是存在的childwidth = view.getMeasuredWidth();//3.根據子視圖的寬度和高度,求出改ViewGroup的寬度和高度childheight = view.getMeasuredHeight();int width = view.getMeasuredWidth() * children;setMeasuredDimension(width,childheight);}}/*** 事件傳遞過程中的調用方法,我們需要調用容器的攔截方法 onInterceptTouchEvent* 針對于該方法我們可以理解為 如果說該方法的返回值為true的時候,那么我們自定義的ViewGroup容器就會處理此次攔截事件* 如果說返回值為false的時候,那么我們自定義的ViewGroup容器將不會接受此次事件的處理過程,將會繼續向下傳遞事件* 針對于我們自定義的ViewGroup 我們希望我們的ViewGroup,容器處理接受事件 那么我們的返回值就是true*/@Overridepublic boolean onInterceptTouchEvent(MotionEvent ev) {return true;}/*** 用2中方式來實現輪播圖的手動輪播* 1.利用 scrollTo、scrollBy 完成輪播圖的手動輪播* 2.利用 Scroller 對象 完成輪播圖的手動輪播** 第一:我們在滑動屏幕圖片的過程中,其實就是 我們自定義ViewGroup的子視圖的移動過程,那么我們只需要知道* 滑動之前的橫坐標和滑動之后的橫坐標,此時 我們就可以 求出次過程中移動的距離,我們在利用 scrollBy方法實現* 圖片的滑動,所以 此時我們需要有2個值要我們求出:移動之前、移動之后的 橫坐標值** 第二:在我們第一次按下的那一瞬間,此時的移動之前和移動之后的值是相等的,也就是我們按下的那一瞬間的那一個點* 的橫坐標的值。** 第三:我們在不斷滑動的過程中,會不斷的調用我們的ACTION_MOVE方法,那么此時我們就應該將移動之前的值* 和移動之后的進行保存,以便我們能夠算出滑動的距離** 第四:在我們抬起的那一瞬間,我們需要計算出我們此時將要滑動到哪張圖片的位置上。** 我們此時就需要求得將要滑動到的哪張圖片的索引值。* (我們當前ViewGroup的滑動距離 + 我們的每一張圖片的寬度 / 2) / 我們的每一張圖片的寬度值** 此時我們就可以利用scrollTo方法。滑動到該圖片的位置上**/@Overridepublic boolean onTouchEvent(MotionEvent event) { // return super.onTouchEvent(event);switch (event.getAction()){case MotionEvent.ACTION_DOWN://表示的是用戶按下的一瞬間stopAuto();if(scroller.isFinished()){//.利用 Scroller 對象 完成輪播圖的手動輪播scroller.abortAnimation();}isClick = true;x = (int) event.getX();break;case MotionEvent.ACTION_MOVE://表示的是用戶 按下之后 在屏幕上移動的過程int moveX = (int) event.getX();int distance = moveX - x;scrollBy(-distance,0);x = moveX;isClick = false;break;case MotionEvent.ACTION_UP://表示的是用戶抬起的一瞬間int scrollX = getScrollX();index = (scrollX + childwidth / 2) / childwidth;if(index < 0) {//說明了此時已經滑倒了最左邊第一張圖片index = 0;}else if(index > children - 1) {//說明滑到了最后一張圖片index = children - 1;}if (isClick){//代表點擊事件lister.clickImageIndex(index);}else {int dx = index * childwidth - scrollX;//.利用 Scroller 對象 完成輪播圖的手動輪播scroller.startScroll(scrollX,0,dx,0);//.利用 Scroller 對象 完成輪播圖的手動輪播postInvalidate();//.利用 Scroller 對象 完成輪播圖的手動輪播 // scrollTo(index * childwidth,0);//利用 scrollTo、scrollBy 完成輪播圖的手動輪播barnnerViewGroupLisnner.selectImage(index);}startAuto();break;default:break;}return true;//我們該容器的父View,我們已經處理好了該事件}/*** 繼承ViewGroup必須要實現布局onLayout方法* @param changed 當我們的ViewGroup布局位置發生變化的為true,沒有發生改變為false* @param l* @param t* @param r* @param b ,沒有發生改變為false*/@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {if(changed){int leftMargin = 0;for(int i = 0;i < children;i++){View view = getChildAt(i);view.layout(leftMargin, 0, leftMargin + childwidth, childheight);leftMargin += childwidth;}}}public interface ImageBarnnerViewGroupLisnner{void selectImage(int index);} }
ImageBarnnerFrameLayout類
/*** Created by hp on 2018/8/2.*/public class ImageBarnnerFrameLayout extends FrameLayout implements ImageBannerViewGroup.ImageBarnnerViewGroupLisnner,ImageBannerViewGroup.ImageBarnnerLister{private ImageBannerViewGroup imageBannerViewGroup;private LinearLayout linearLayout;private FramLayoutLisenner lisenner;public FramLayoutLisenner getLisenner() {return lisenner;}public void setLisenner(FramLayoutLisenner lisenner) {this.lisenner = lisenner;}public ImageBarnnerFrameLayout(@NonNull Context context) {super(context);initImageBannerViewGroup();initDotLinearlayout();}public ImageBarnnerFrameLayout(@NonNull Context context, @Nullable AttributeSet attrs) {super(context, attrs);initImageBannerViewGroup();initDotLinearlayout();}public ImageBarnnerFrameLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);initImageBannerViewGroup();initDotLinearlayout();}public void addBitmaps(List<Bitmap> list){for(int i = 0;i < list.size();i++){Bitmap bitmap = list.get(i);addBitmapToImageBarnnerViewGroup(bitmap);addDotToLinearlayout();}}private void addDotToLinearlayout(){ImageView iv = new ImageView(getContext());LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);lp.setMargins(5,5,5,5);iv.setLayoutParams(lp);iv.setImageResource(R.drawable.dot_normal);linearLayout.addView(iv);}private void addBitmapToImageBarnnerViewGroup(Bitmap bitmap){ImageView iv = new ImageView(getContext());iv.setScaleType(ImageView.ScaleType.CENTER_CROP);iv.setLayoutParams(new ViewGroup.LayoutParams(C.WITTH,ViewGroup.LayoutParams.WRAP_CONTENT));iv.setImageBitmap(bitmap);imageBannerViewGroup.addView(iv);}/*** 初始化我們自定義的圖片輪播功能的核心*/private void initImageBannerViewGroup(){imageBannerViewGroup = new ImageBannerViewGroup(getContext());FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT);imageBannerViewGroup.setLayoutParams(lp);imageBannerViewGroup.setBarnnerViewGroupLisnner(this);//這里就是將Lisnner傳遞給FramlayoutimageBannerViewGroup.setLister(this);addView(imageBannerViewGroup);}/*** 初始化 底部圓點 布局*/private void initDotLinearlayout(){linearLayout = new LinearLayout(getContext());FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT,40);linearLayout.setLayoutParams(lp);linearLayout.setOrientation(LinearLayout.HORIZONTAL);linearLayout.setGravity(Gravity.CENTER);linearLayout.setBackgroundColor(Color.RED);addView(linearLayout);FrameLayout.LayoutParams layoutParams = (LayoutParams) linearLayout.getLayoutParams();layoutParams.gravity = Gravity.BOTTOM;linearLayout.setLayoutParams(layoutParams);/*** 設置透明度* 在3.0以后,我們使用的是setAlpha(),在3.0之前我們使用的也是setAlpha(),但是調用者不同*/if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB){linearLayout.setAlpha(0.5f);}else {linearLayout.getBackground().setAlpha(100);}}@Overridepublic void selectImage(int index) {int count = linearLayout.getChildCount();for(int i = 0;i < count;i++){ImageView iv = (ImageView) linearLayout.getChildAt(i);if(i == index){iv.setImageResource(R.drawable.dot_select);}else {iv.setImageResource(R.drawable.dot_normal);}}}@Overridepublic void clickImageIndex(int pos) {lisenner.clickImageIndex(pos);}public interface FramLayoutLisenner{void clickImageIndex(int pos);}
}
?MainActivity類
public class MainActivity extends AppCompatActivity implements ImageBarnnerFrameLayout.FramLayoutLisenner {private ImageBarnnerFrameLayout mGroup;private int[] ids = new int[]{R.drawable.d,R.drawable.a,R.drawable.b,R.drawable.c};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//我們需要計算出我們當前手機的寬度DisplayMetrics dm = new DisplayMetrics();getWindowManager().getDefaultDisplay().getMetrics(dm);C.WITTH = dm.widthPixels;mGroup = (ImageBarnnerFrameLayout)findViewById(R.id.image_group);mGroup.setLisenner(this);List<Bitmap> list = new ArrayList<>();for (int i = 0;i < ids.length;i++){Bitmap bitmap = BitmapFactory.decodeResource(getResources(),ids[i]);list.add(bitmap);}mGroup.addBitmaps(list);/* for (int i = 0;i < ids.length;i++){ImageView iv = new ImageView(this);iv.setScaleType(ImageView.ScaleType.CENTER_CROP);iv.setLayoutParams(new ViewGroup.LayoutParams(width,ViewGroup.LayoutParams.WRAP_CONTENT));iv.setImageResource(ids[i]);mGroup.addView(iv);}mGroup.setLister(this);*/}public void clickImageIndex(int pos){Toast.makeText(this,"pos = "+pos,Toast.LENGTH_SHORT).show();} }C類
public class C {public static int WITTH = 0; }布局文件
<?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"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context="com.example.hp.zzdlunbo7.MainActivity"><com.example.hp.zzdlunbo7.view.ImageBarnnerFrameLayoutandroid:id="@+id/image_group"android:layout_width="match_parent"android:layout_height="200dp"></com.example.hp.zzdlunbo7.view.ImageBarnnerFrameLayout></RelativeLayout>導包時要注意,有的包java和Android都有,出錯可能就是導入了java的包
?
代碼是根據慕課上的老師的課程寫的,老師講的很好,強烈建議大家去聽,講解的很詳細,收獲很大
老師課程鏈接https://www.imooc.com/learn/793
總結
以上是生活随笔為你收集整理的Android使用viewpager实现图片轮播效果的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: keil分散加载文件sct写法
- 下一篇: BT原理分析(转)