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

来源:互联网 发布:程序员微电影 编辑:程序博客网 时间:2024/06/09 17:31
  • 自定义轮播图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();            }        });    }}
2 1
原创粉丝点击