- 自定义轮播图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(); } }); }}