欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

安卓轮播图片的实现

程序员文章站 2022-07-14 12:53:57
...

一、原理

首先,将这些要轮播的图片和一些文本分别放置在不同的数据集合中,程序启动的时候默认显示一组图片和文本数据,然后启动一个定时器,每隔一段时间便替换掉显示的图片和文本数据,同时加入一些动画效果,已达到轮播的特效。同时,我们也要实现手指滑动图片达到轮播的效果。

二、实现

1、程序启动界面MainActivity

public class MainActivity extends AppCompatActivity implements ImageBannerFramLayout.FramLayoutLisenner{
    private ImageBannerFramLayout mGroup;
    private int[] ids = new int[] {
            R.drawable.i1,//图片资源1
            R.drawable.i2,//图片资源2
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //计算当前手机宽度
        DisplayMetrics displayMetrics = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
        int width = displayMetrics.widthPixels;
        mGroup = (ImageBannerFramLayout) 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);
    }

    @Override
    public void chickImageIndex(int pos) {
        Toast.makeText(this,"索引值 = " + pos,Toast.LENGTH_SHORT).show();
    }
}

2、新建包view下面新建两个类

1)新建ImageBarnnerViewGroup类继承自ViewGroup

public class ImageBarnnerViewGroup extends ViewGroup {
    private int children;//我们View Group的子视图总个数
    private int childwidth;//子视图的宽度
    private int childheight;//子视图的高度

    private int x;//此时的x的值代表的是第一次按下的位置的横坐标,每一次移动过的过程中 移动之前的位置横坐标
    private int index = 0;//代表名为每张图片的索引
    private Scroller scroller;

    /**
     * 利用一个单击变量开关进行判断,离开屏幕的一瞬间判断用户的操作是点击
     */
    private boolean isClick;//true的时候点击事件,false的时候不是点击事件
    private ImageBarnnerLister lister;

    private ImageBarnnerViewGroupLisnner barnnerViewGroupLisnner;

    public ImageBarnnerLister getLister() {
        return lister;
    }

    public void setLister(ImageBarnnerLister lister) {
        this.lister = lister;
    }

    public ImageBarnnerViewGroupLisnner getBarnnerViewGroupLisnner() {
        return barnnerViewGroupLisnner;
    }
    public void setBarnnerViewGroupLisnner(ImageBarnnerViewGroupLisnner barnnerViewGroupLisnner) {
        this.barnnerViewGroupLisnner = barnnerViewGroupLisnner;
    }
    public interface ImageBarnnerLister {
        void chickImageIndex(int pos);//pos代表的是我们当前的图片的具体索引值
    }
    /**
     * 实现轮播图底部圆点切换效果
     * 自定义一个继承自FragmenLayou布局,利用FragmeLayout布局特性
     */
    
    //自动轮播
    private boolean isAuto = true;//默认情况下开启轮播
    private Timer timer = new Timer();
    private TimerTask timerTask;
    
    @SuppressLint("HandlerLeak")
    private android.os.Handler autohandler = new android.os.Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case 0://我们需要图片的自动轮播
                    if (++index >= children) {//如果是最后一张图片,从第一张开始
                        index = 0;
                    }
                    scrollTo(childwidth * index,0);
                    barnnerViewGroupLisnner.selectImage(index);
                    break;
                default:
            }
        }
    };

    private void startAuto() {
        isAuto = true;

    }

    private void stopAuto() {
        isAuto = false;
    }

    /**
     * 采用Timer,TimerTask,Handler三者结合的方式来实现自动轮播
     */

    public ImageBarnnerViewGroup(Context context) {
        super(context);
        initObj();
    }

    public ImageBarnnerViewGroup(Context context, AttributeSet attrs) {
        super(context, attrs);
        initObj();
    }

    public ImageBarnnerViewGroup(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        initObj();
    }


    private void initObj() {
        scroller = new Scroller(getContext());

        timerTask = new TimerTask() {
            @Override
            public void run() {
                if (isAuto) {//开启轮播图
                    autohandler.sendEmptyMessage(0);
                }
            }
        };
        timer.schedule(timerTask,100,3000);
    }

    @Override
    public void computeScroll() {
        super.computeScroll();
        if (scroller.computeScrollOffset()) {
            scrollTo(scroller.getCurrX(),0);
            invalidate();//重绘
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //1.求出子视图的个数
        children = getChildCount();//我们可以知道自试图的个数
        if (0 == children)
        {
            setMeasuredDimension(0,0);
        } else {
            measureChildren(widthMeasureSpec, heightMeasureSpec);
            //此时我们以第一个子视图=为基准,也就是说我们的View Group
            View view = getChildAt(0);
            childwidth = view.getMeasuredWidth();
            childheight = view.getMeasuredHeight();
            int width = view.getMeasuredWidth() * children;
            setMeasuredDimension(width,childheight);
        }
        //2.测量子视图的宽度和高度
        //3.根据子视图的狂赌和高度,求出该ViewGroup的宽度和高度
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return super.onInterceptTouchEvent(ev);
    }
    /**
     * 用两种方式来实现轮播图的手动轮播
     * 1,利用scrollTo,scrollBy 完成轮播图的手动轮播
     * 1,利用Scroller 对象完成轮播图的手动效果
     * @param event
     * @return
     */

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN://表示用户按下的一瞬间
                stopAuto();//停止图片轮播
                if (!scroller.isFinished()) {
                    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.chickImageIndex(index);
                } else {
                    int dx = index * childwidth - scrollX;
                    scroller.startScroll(scrollX,0,dx,0);
                    postInvalidate();
                    barnnerViewGroupLisnner.selectImage(index);
                }
                startAuto();//开启图片轮播
                break;
            default:
        }
        return true;
        //返回true的目的是告诉该View Group容器的父View 我们已经处理好了该事件
    }

    @Override
    protected void onLayout(boolean b, int i, int i1, int i2, int i3) {
        if (b) {
            int lefrMargin = 0;
            for (int j = 0; j < children; j++) {
                View view = getChildAt(j);
                view.layout(lefrMargin,0,lefrMargin + childwidth,childheight);
                lefrMargin += childwidth;
            }
        }
    }

    public interface ImageBarnnerViewGroupLisnner{
        void selectImage(int index);
    }
}

2)新建ImageBannerFramLayout类继承自FrameLayout实现两个接口

public class ImageBannerFramLayout extends FrameLayout implements ImageBarnnerViewGroup.ImageBarnnerViewGroupLisnner,ImageBarnnerViewGroup.ImageBarnnerLister{

    private ImageBarnnerViewGroup imageBarnnerViewGroup;
    private LinearLayout linearLayout;

    private FramLayoutLisenner lisenner;

    public FramLayoutLisenner getLisenner() {
        return lisenner;
    }

    public void setLisenner(FramLayoutLisenner lisenner) {
        this.lisenner = lisenner;
    }

    public ImageBannerFramLayout(@NonNull Context context) {
        super(context);
        initImageBarnnerViewGroup();
        initDotLinearlayout();
    }



    public ImageBannerFramLayout(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        initImageBarnnerViewGroup();
        initDotLinearlayout();
    }

    public ImageBannerFramLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initImageBarnnerViewGroup();
        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 layoutParams = new LinearLayout.LayoutParams
                (LinearLayout.LayoutParams.WRAP_CONTENT,LinearLayout.LayoutParams.MATCH_PARENT);
        layoutParams.setMargins(5,5,5,5);
        iv.setLayoutParams(layoutParams);
        iv.setImageResource(R.drawable.dot_normal);
        linearLayout.addView(iv);
    }

    private void addBitmapToImageBarnnerViewGroup(Bitmap bitmap) {
        ImageView imageView = new ImageView(getContext());
        imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
        imageView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT));
        imageView.setImageBitmap(bitmap);
        imageBarnnerViewGroup.addView(imageView);
    }

    //初始化自定义图片轮播功能核心类
    private void initImageBarnnerViewGroup() {
        imageBarnnerViewGroup = new ImageBarnnerViewGroup(getContext());
        FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams
                (FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
        imageBarnnerViewGroup.setLayoutParams(layoutParams);
        imageBarnnerViewGroup.setBarnnerViewGroupLisnner(this);//将linsnner传递给Framlayout
        imageBarnnerViewGroup.setLister(this);
        addView(imageBarnnerViewGroup);
    }

    //初始化底部圆点布局
    private void initDotLinearlayout() {
        linearLayout = new LinearLayout(getContext());
        FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams
                (FrameLayout.LayoutParams.MATCH_PARENT, 40);
        linearLayout.setLayoutParams(layoutParams);
        linearLayout.setOrientation(LinearLayout.HORIZONTAL);
        linearLayout.setGravity(Gravity.CENTER);

        linearLayout.setBackgroundColor(Color.RED);
        addView(linearLayout);

        FrameLayout.LayoutParams layoutParams1 = (LayoutParams) linearLayout.getLayoutParams();
        layoutParams.gravity = Gravity.BOTTOM;
        linearLayout.setLayoutParams(layoutParams1);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
            linearLayout.setAlpha(0.5f);
        } else {
            linearLayout.getBackground().setAlpha(100);
        }
    }


    @Override
    public 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);
            }
        }
    }

    @Override
    public void chickImageIndex(int pos) {
        lisenner.chickImageIndex(pos);
    }

    public interface FramLayoutLisenner{
        void chickImageIndex(int pos);
    }
}

3、程序布局页面activity_main

<?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=".MainActivity">
    <com.example.tony.imagegroup.view.ImageBannerFramLayout
        android:id="@+id/image_group"
        android:layout_width="match_parent"
        android:layout_height="200dp">
    </com.example.tony.imagegroup.view.ImageBannerFramLayout>
</RelativeLayout>

4、新建两个drawable资源文件dot_normal.xml和dot_select.xml,实现轮播图底部小圆点

不同的是前者颜色为白色后者为黑色

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="oval">
    <solid android:color="@android:color/white"/>
    <size android:height="10dp"
        android:width="10dp"/>
</shape>

三、运行结果

安卓轮播图片的实现