Android轮播图封装,下拉刷新相结合

Posted 星火燎原2016

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android轮播图封装,下拉刷新相结合相关的知识,希望对你有一定的参考价值。

  • 自定义轮播图CarouselView
  • 自定义下拉刷新PullRefreshListView

马上就要正式做毕业设计了,一些零碎时间写其中的一个模块,现记录下来,以备以后忘记时使用。欢迎大神不吝纠正。

效果图:
技术分享

layout_carousel.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    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="250dp">
    </android.support.v4.view.ViewPager>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignBottom="@id/viewPager"
        android:background="#55000000"
        android:orientation="vertical"
        android:padding="10dp">

        <TextView
            android:id="@+id/tv_title"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center_horizontal"
            android:textColor="#fff" />

        <LinearLayout
            android:id="@+id/dot_layout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="5dp"
            android:gravity="center_horizontal"
            android:orientation="horizontal">
        </LinearLayout>
    </LinearLayout>
</RelativeLayout>

carousel_dot_selected.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" />
</shape>

carousel_dot_unselect.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="oval">
    <solid android:color="#77000000" />
</shape>

carousel_dot_selector.xml (轮播图指示点选择器)

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/carousel_dot_selected"                   android:state_enabled="true" />
 <item android:drawable="@drawable/carousel_dot_unselect" android:state_enabled="false" />
</selector>

轮播图数据bean

package com.xing.carousel;

/**
 * Created by Administrator on 2016/3/22.
 */
public class CarouselData {
    private int id;

    private String title;

    private int resId;

    public CarouselData(int id, String title, int resId) {
        this.id = id;
        this.title = title;
        this.resId = resId;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public int getResId() {
        return resId;
    }

    public void setResId(int resId) {
        this.resId = resId;
    }

    @Override
    public String toString() {
        return "CarouselData{" +
                "id=" + id +
                ", title=‘" + title + ‘\‘‘ +
                ", resId=" + resId +
                ‘}‘;
    }
}

自定义轮播图CarsouselView.java

package com.xing.carousel;

import android.content.Context;
import android.graphics.Color;
import android.os.Handler;
import android.os.Message;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by Administrator on 2016/3/22.
 */
public class CarouselView extends LinearLayout {

    private Context context;

    private List<CarouselData> carouselDataList;

    private ViewPager viewPager;

    private TextView tv_title;

    private LinearLayout dotLayout;

    private List<View> dotList;   //指示点

    private static final int MSG_UPDATE = 1;


    private Handler handler;


    public CarouselView(Context context) {
        this(context, null);
    }

    public CarouselView(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.context = context;
        init();
    }

    private void init() {
        LayoutInflater.from(context).inflate(R.layout.layout_carousel, this, true);
        initView();
        initData();

    }

    private void initData() {
        dotList = new ArrayList<>();
    }


    private void initView() {
        viewPager = (ViewPager) findViewById(R.id.viewPager);
        tv_title = (TextView) findViewById(R.id.tv_title);
        dotLayout = (LinearLayout) findViewById(R.id.dot_layout);
    }


    public void start(List<CarouselData> carouselDataList) {
        this.carouselDataList = carouselDataList;
        if (this.carouselDataList == null || this.carouselDataList.size() < 1) {
            return;
        }
        View view = null;
        LayoutParams params = new LayoutParams(5, 5);
        //根据轮播图要显示的数量来创建指示点的个数
        for (int i = 0; i < this.carouselDataList.size(); i++) {
            view = new View(context);
            //设置dot的宽和高,相当于在xml中设置layout_height和layout_width
            if (i != 0) {  //设置左边距
                params.leftMargin = 5;
            }
            view.setLayoutParams(params);
            view.setBackgroundResource(R.drawable.carousel_dot_selector);
            dotList.add(view);  //加入到list集合中
            dotLayout.addView(view);  //加入父布局
        }

        viewPager.setAdapter(new MyPagerAdapter());

        viewPager.setOnPageChangeListener(new MyPagerChangeListener());

        updateTitleDot();

        if (handler == null) {
            handler = new Handler() {
                @Override
                public void handleMessage(Message msg) {
                    super.handleMessage(msg);
                    switch (msg.what) {
                        case MSG_UPDATE:
                            int currentItem = viewPager.getCurrentItem();
                            if (currentItem < CarouselView.this.carouselDataList.size() - 1) {  //从0开始
                                currentItem++;
                            } else {
                                currentItem = 0;
                            }
                            viewPager.setCurrentItem(currentItem);
                            handler.sendEmptyMessageDelayed(MSG_UPDATE, 2000);
                            break;
                    }

                }
            };
            handler.sendEmptyMessageDelayed(MSG_UPDATE, 2000);
        }



    }


    class MyPagerAdapter extends PagerAdapter {

        @Override
        public int getCount() {
            return carouselDataList.size();
        }

        @Override
        public boolean isViewFromObject(View view, Object object) {
            return view == object;

        }


        @Override
        public Object instantiateItem(ViewGroup container, final int position) {
            final CarouselData carouselData = carouselDataList.get(position);
            ImageView imageView = new ImageView(context);
            imageView.setImageResource(carouselData.getResId());
            imageView.setScaleType(ImageView.ScaleType.FIT_XY);
            container.addView(imageView);

            imageView.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View view) {
                    clickCallback.onClick(carouselData.getId(), position);
                }
            });
            return imageView;
        }

        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            container.removeView((View) object);
        }
    }


    class MyPagerChangeListener implements ViewPager.OnPageChangeListener {

        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

        }

        @Override
        public void onPageSelected(int position) {
            updateTitleDot();
        }

        @Override
        public void onPageScrollStateChanged(int state) {

        }
    }

    private void updateTitleDot() {
        int currentPosition = viewPager.getCurrentItem() % carouselDataList.size();
        CarouselData carouselData = carouselDataList.get(currentPosition);
        tv_title.setText(carouselData.getTitle());
        for (int i = 0; i < carouselDataList.size(); i++) {
            dotLayout.getChildAt(i).setEnabled(i == currentPosition);
        }
    }


    ClickCallback clickCallback;

    interface ClickCallback {
        void onClick(int id, int position);
    }

    public void setClickCallback(ClickCallback clickCallback) {
        this.clickCallback = clickCallback;
    }
}

圆形进度条
progressbar_rotate.xml

<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromDegrees="0"
    android:pivotX="50%"
    android:pivotY="50%"
    android:toDegrees="360">

    <shape
        android:innerRadius="12dp"
        android:shape="ring"
        android:thickness="3dp"
        android:useLevel="false">

        <!--android:useLevel="false"用于禁止progressbar自己转圈,自己在外层套一个rotate,用于转圈-->

        <gradient
            android:centerColor="@color/progressbar_center_color"
            android:endColor="@color/progressbar_end_color"
            android:startColor="@color/progressbar_start_color" />
    </shape>
</rotate>

下拉刷新控件

1.ListView头布局
layout_pull_listview_header.xml

<?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="match_parent"
    android:gravity="center_horizontal"
    android:orientation="horizontal">

    <!--android:padding不能使用,因为该布局将会以addHeaderview方式添加到listview,可用margin代替。-->


    <FrameLayout
        android:id="@+id/fl_progressbar_arrow"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        android:layout_marginBottom="8dp">

        <ProgressBar
            android:id="@+id/pb_refresh"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:indeterminateDrawable="@drawable/progressbar_rotate"
            android:visibility="invisible" />

        <ImageView
            android:id="@+id/iv_arrow"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:src="@mipmap/ic_pulltorefresh_arrow" />
    </FrameLayout>

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="10dp"
        android:layout_marginTop="8dp"
        android:layout_marginBottom="8dp"
        android:gravity="center_horizontal"
        android:orientation="vertical">

        <TextView
            android:id="@+id/tv_listview_top_tip"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="3dp"
            android:text="正在刷新"
            android:textColor="@color/colorPrimary" />


        <TextView
            android:id="@+id/tv_listview_top_time"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="3dp"
            android:text="最新刷新时间 2016-3-13"
            android:textColor="@color/colorPrimary" />

    </LinearLayout>

</LinearLayout>

ListView底部布局
layout_pull_listview_footer.xml

<?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:gravity="center"
    android:orientation="horizontal">

    <ProgressBar
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="5dp"
        android:layout_marginTop="5dp"
        android:indeterminateDrawable="@drawable/progressbar_rotate" />


    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="5dp"
        android:layout_marginLeft="10dp"
        android:layout_marginTop="5dp"
        android:text="@string/loading_more" />


</LinearLayout>

PullRefreshListView.java

package com.xing.carousel;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.RotateAnimation;
import android.widget.AbsListView;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;

import java.util.Date;

/**
 * Created by Administrator on 2016/3/19.
 */
public class PullRefreshListView extends ListView implements AbsListView.OnScrollListener {

    private Context context;

    private View headerView;

    private final int STATE_PULL_REFRESH = 0;

    private final int STATE_RELEASE_REFRESH = 1;

    private final int STATE_REFRESHING = 2;

    private int currentState = STATE_PULL_REFRESH;

    private TextView mRefreshStatusTip;

    private TextView mRefreshTime;

    private ProgressBar mProgressBar;

    private ImageView mArrowImg;

    private int headerViewHeight;

    private int startY = -1;   //初始值

    private RotateAnimation upAnimation;

    private RotateAnimation downAnimation;

    private View footerView;

    private int footerViewHeight;

    public PullRefreshListView(Context context) {
        this(context, null);
    }

    public PullRefreshListView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    private void init() {
        context = getContext();
        initView();
        initData();


    }

    private void initData() {
        //初始化头布局
        headerView.measure(0, 0);
        //得到头布局高度
        headerViewHeight = headerView.getMeasuredHeight();
        //设置上边距,隐藏头布局
        headerView.setPadding(0, -headerViewHeight, 0, 0);
        //将头布局添加至listView中
        this.addHeaderView(headerView, null, false); //头布局selectable=false

        //初始化底部布局数据
        footerView.measure(0, 0);
        footerViewHeight = footerView.getMeasuredHeight();
        footerView.setPadding(0, 0, 0, -footerViewHeight);
        this.addFooterView(footerView, null, false);

        //初始化动画
        initAnimation();

    }


    private void initView() {
        //初始化listView头布局
        headerView = View.inflate(context, R.layout.layout_pull_listview_header, null);
        mProgressBar = (ProgressBar) headerView.findViewById(R.id.pb_refresh);
        mArrowImg = (ImageView) headerView.findViewById(R.id.iv_arrow);
        mRefreshStatusTip = (TextView) headerView.findViewById(R.id.tv_listview_top_tip);
        mRefreshTime = (TextView) headerView.findViewById(R.id.tv_listview_top_time);

        //初始化底部布局
        footerView = View.inflate(context, R.layout.layout_pull_listview_footer, null);

    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                startY = (int) event.getRawY();
                break;
            case MotionEvent.ACTION_MOVE:

                //如果当前正在刷新,则不处理
                if (currentState == STATE_REFRESHING) {
                    break;
                }

                if (startY == -1) {
                    startY = (int) event.getRawY();   //保证startY有值
                }
                int deltaY = (int) (event.getRawY() - startY);  //手指移动的偏移量
                if (deltaY > 0 && getFirstVisiblePosition() == 0) {  //只有手指向下滑动(deltaY>0)并且第一个item为可见的时候,才下拉刷新
                    int paddingTop = -headerViewHeight + deltaY;
                    headerView.setPadding(0, paddingTop, 0, 0);  //将更新的padding设置给headerview,实时更新下拉布局的位置
                    if (paddingTop > 0 && currentState != STATE_RELEASE_REFRESH) {
                        currentState = STATE_RELEASE_REFRESH;
                        mArrowImg.startAnimation(upAnimation);
                    } else if (paddingTop < 0 && currentState != STATE_PULL_REFRESH) {
                        currentState = STATE_PULL_REFRESH;
                        mArrowImg.startAnimation(downAnimation);
                    }
                    return true;  //拦截move事件,不让listview处理
                }
                break;

            case MotionEvent.ACTION_UP:

                startY = -1;  //重置

                if (currentState == STATE_PULL_REFRESH) {  //手指抬起时,如果当前状态是下拉刷新,则直接隐藏头布局。
                    headerView.setPadding(0, -headerViewHeight, 0, 0);

                } else if (currentState == STATE_RELEASE_REFRESH) {   //手指抬起时,如果当前状态是松开刷新,则进入正在刷新状态
                    currentState = STATE_REFRESHING;
                    //显示正在刷新状态
                    headerView.setPadding(0, 0, 0, 0);
                    //更新当前状态
                    refreshHeaderState(currentState);

                    //监听回调
                    if (onRefreshListener != null) {
                        onRefreshListener.onRefresh();
                    }
                }
                break;
        }
        return super.onTouchEvent(event);
    }


    private void refreshHeaderState(int currentState) {
        switch (currentState) {
            case STATE_PULL_REFRESH:
                mRefreshStatusTip.setText(getResources().getString(R.string.state_pull_refresh));
                mArrowImg.setVisibility(View.VISIBLE);
                mProgressBar.setVisibility(View.INVISIBLE);
                break;
            case STATE_RELEASE_REFRESH:
                mRefreshStatusTip.setText(getResources().getString(R.string.state_release_refresh));
                mArrowImg.setVisibility(View.VISIBLE);
                mProgressBar.setVisibility(View.INVISIBLE);
                break;
            case STATE_REFRESHING:
                mRefreshStatusTip.setText(getResources().getString(R.string.state_refreshing));
                mArrowImg.clearAnimation();  //清除动画才能设置其可见性
                mArrowImg.setVisibility(View.INVISIBLE);
                mProgressBar.setVisibility(View.VISIBLE);
                mRefreshTime.setText(getResources().getString(R.string.last_refresh_time));
                break;
        }
    }


    private void initAnimation() {
        //向上旋转动画
        upAnimation = new RotateAnimation(0, -180, RotateAnimation.RELATIVE_TO_SELF, 0.5f,
                RotateAnimation.RELATIVE_TO_SELF, 0.5f);
        upAnimation.setDuration(300);
        upAnimation.setFillAfter(true);
        //向下旋转动画
        downAnimation = new RotateAnimation(-180, -360, RotateAnimation.RELATIVE_TO_SELF, 0.5f,
                RotateAnimation.RELATIVE_TO_SELF, 0.5f);
        downAnimation.setDuration(300);
        downAnimation.setFillAfter(true);
    }


    /**
     * 重置headerview中的刷新状态和progressbar的显示
     */
    public void resetHeaderFooterView() {
        currentState = STATE_PULL_REFRESH;
        mRefreshStatusTip.setText(getResources().getString(R.string.state_pull_refresh));
        mArrowImg.setVisibility(View.VISIBLE);
        mProgressBar.setVisibility(View.INVISIBLE);
    }

    interface OnRefreshListener {
        void onRefresh();

        void loadMore();  //加载更多,通过listview的滚动监听实现
    }

    OnRefreshListener onRefreshListener;

    public void setOnRefreshListener(OnRefreshListener onRefreshListener) {
        this.onRefreshListener = onRefreshListener;
    }


    /**
     * ListView的滑动监听
     *
     * @param view
     * @param scrollState
     */
    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
        if (scrollState == OnScrollListener.SCROLL_STATE_FLING || scrollState == OnScrollListener.SCROLL_STATE_IDLE) {
            if (getLastVisiblePosition() == getCount() - 1) {   //滑动到最后一条,显示tooterView
                footerView.setPadding(0, 0, 0, 0);
                setSelection(getCount() - 1);  //将最后一条拉到屏幕中显示,这样,footerview就可以显示出来了,否则,footerview需要再次滑动才能显示在屏幕中
            }
        }

    }

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {

    }


}

新建Android Project 测试demo

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.xing.carousel.MainActivity">

    <com.xing.carousel.PullRefreshListView
        android:id="@+id/listView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>

轮播图作为头布局添加到PullRefreshListView中
layout_header.xml

<?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">

    <com.xing.carousel.CarouselView
        android:id="@+id/carsouelView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</LinearLayout>

MainActivity.java

package com.xing.carousel;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {

    private CarouselView carouselView;

    private List<CarouselData> carouselDataList;

    private PullRefreshListView listView;


    private int[] resIds = {R.mipmap.ic_launcher, R.mipmap.top2, R.mipmap.back2};

    private List<String> data;

    private View headerView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        listView = (PullRefreshListView) findViewById(R.id.listView);
        headerView = View.inflate(this, R.layout.layout_header, null);
        carouselView = (CarouselView) headerView.findViewById(R.id.carsouelView);
        carouselDataList = new ArrayList<>();
        for (int i = 0; i < resIds.length; i++) {
            carouselDataList.add(new CarouselData(i, "标题" + i, resIds[i]));
        }

        carouselView.start(carouselDataList);
        data = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            data.add("ListView---->" + i);
        }

        listView.addHeaderView(headerView);
        listView.setAdapter(new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, data));

        carouselView.setClickCallback(new CarouselView.ClickCallback() {
            @Override
            public void onClick(int id, int position) {
                Toast.makeText(MainActivity.this, "你点击了第" + position + "项", Toast.LENGTH_SHORT).show();
            }
        });


    }


}





以上是关于Android轮播图封装,下拉刷新相结合的主要内容,如果未能解决你的问题,请参考以下文章

上下拉刷新 轮播图 listview

Android 解决下拉刷新控件和ScrollVIew的滑动冲突问题。

用原生js封装轮播图

Android轮播图

Android常用功能:轮播图从 0 到 1的开发如何做?

原生JS面向对象思想封装轮播图组件