安卓轮播图片的实现

一、原理

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

二、实现

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>

三、运行结果

猜你喜欢

转载自blog.csdn.net/qq_18378065/article/details/82711618
今日推荐