标签:
public class RefreshListView extends ListView implements OnScrollListener,android.widget.AdapterView.OnItemClickListener {private static final int STATE_PULL_REFRESH = 0;// 下拉刷新private static final int STATE_RELEASE_REFRESH = 1;// 松开刷新private static final int STATE_REFRESHING = 2;// 正在刷新private View mHeaderView;private int startY = -1;// 滑动起点的y坐标private int mHeaderViewHeight;private int mCurrrentState = STATE_PULL_REFRESH;// 当前状态private TextView tvTitle;private TextView tvTime;private ImageView ivArrow;private ProgressBar pbProgress;private RotateAnimation animUp;private RotateAnimation animDown;public RefreshListView(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);initHeaderView();initFooterView();}public RefreshListView(Context context, AttributeSet attrs) {super(context, attrs);initHeaderView();initFooterView();}public RefreshListView(Context context) {super(context);initHeaderView();initFooterView();}/*** 初始化头布局*/private void initHeaderView() {mHeaderView = View.inflate(getContext(), R.layout.refresh_header, null);this.addHeaderView(mHeaderView);tvTitle = (TextView) mHeaderView.findViewById(R.id.tv_title);tvTime = (TextView) mHeaderView.findViewById(R.id.tv_time);ivArrow = (ImageView) mHeaderView.findViewById(R.id.iv_arr);pbProgress = (ProgressBar) mHeaderView.findViewById(R.id.pb_progress);mHeaderView.measure(0, 0);//测量之后该view的getMeasuredHeight()就会返回刚才测量所得的高,getMeasuredWidth返回测量所得宽mHeaderViewHeight = mHeaderView.getMeasuredHeight();mHeaderView.setPadding(0, -mHeaderViewHeight, 0, 0);// 隐藏头布局initArrowAnim();tvTime.setText("最后刷新时间:" + getCurrentTime());}/** 初始化脚布局*/private void initFooterView() {mFooterView = View.inflate(getContext(),R.layout.refresh_listview_footer, null);this.addFooterView(mFooterView);mFooterView.measure(0, 0);mFooterViewHeight = mFooterView.getMeasuredHeight();mFooterView.setPadding(0, -mFooterViewHeight, 0, 0);// 隐藏this.setOnScrollListener(this);//加载更多需要实现OnScrollListener接口}@Overridepublic boolean onTouchEvent(MotionEvent ev) {//下拉刷新需要重写这个方法:触摸事件switch (ev.getAction()) {case MotionEvent.ACTION_DOWN:startY = (int) ev.getRawY();break;case MotionEvent.ACTION_MOVE:if (startY == -1) {// 确保startY有效,有时候ACTION_DOWN事件不会调用,需要重新掉一次startY = (int) ev.getRawY();}if (mCurrrentState == STATE_REFRESHING) {// 正在刷新时不做处理break;}int endY = (int) ev.getRawY();int dy = endY - startY;// 移动便宜量if (dy > 0 && getFirstVisiblePosition() == 0) {// 只有下拉并且当前是第一个item,才允许下拉int padding = dy - mHeaderViewHeight;// 计算paddingmHeaderView.setPadding(0, padding, 0, 0);// 设置当前paddingif (padding > 0 && mCurrrentState != STATE_RELEASE_REFRESH) {// 状态改为松开刷新,头布局全部出来了mCurrrentState = STATE_RELEASE_REFRESH;refreshState();} else if (padding < 0 && mCurrrentState != STATE_PULL_REFRESH) {// 改为下拉刷新状态mCurrrentState = STATE_PULL_REFRESH;refreshState();}return true;}break;case MotionEvent.ACTION_UP:startY = -1;// 重置if (mCurrrentState == STATE_RELEASE_REFRESH) {mCurrrentState = STATE_REFRESHING;// 正在刷新mHeaderView.setPadding(0, 0, 0, 0);// 显示refreshState();} else if (mCurrrentState == STATE_PULL_REFRESH) {mHeaderView.setPadding(0, -mHeaderViewHeight, 0, 0);// 隐藏}break;default:break;}return super.onTouchEvent(ev);}/*** 刷新下拉控件的布局*/private void refreshState() {switch (mCurrrentState) {case STATE_PULL_REFRESH:tvTitle.setText("下拉刷新");ivArrow.setVisibility(View.VISIBLE);pbProgress.setVisibility(View.INVISIBLE);ivArrow.startAnimation(animDown);//箭头向下break;case STATE_RELEASE_REFRESH:tvTitle.setText("松开刷新");ivArrow.setVisibility(View.VISIBLE);pbProgress.setVisibility(View.INVISIBLE);ivArrow.startAnimation(animUp);break;case STATE_REFRESHING:tvTitle.setText("正在刷新...");ivArrow.clearAnimation();// 必须先清除动画,才能隐藏ivArrow.setVisibility(View.INVISIBLE);pbProgress.setVisibility(View.VISIBLE);if (mListener != null) {mListener.onRefresh();//不等于空时才刷新数据}break;default:break;}}/*** 初始化箭头动画*/private void initArrowAnim() {// 箭头向上动画animUp = new RotateAnimation(0, -180, Animation.RELATIVE_TO_SELF, 0.5f,Animation.RELATIVE_TO_SELF, 0.5f);animUp.setDuration(200);animUp.setFillAfter(true);// 箭头向下动画animDown = new RotateAnimation(-180, 0, Animation.RELATIVE_TO_SELF,0.5f, Animation.RELATIVE_TO_SELF, 0.5f);animDown.setDuration(200);animDown.setFillAfter(true);}OnRefreshListener mListener;private View mFooterView;private int mFooterViewHeight;public void setOnRefreshListener(OnRefreshListener listener) {mListener = listener;}public interface OnRefreshListener {//定义个接口public void onRefresh();public void onLoadMore();// 加载下一页数据}/** 收起下拉刷新的控件*/public void onRefreshComplete(boolean success) {//加了个参数,成功才更新时间if (isLoadingMore) {// 正在加载更多...如果是加载下一页mFooterView.setPadding(0, -mFooterViewHeight, 0, 0);// 隐藏脚布局,isLoadingMore = false;} else {mCurrrentState = STATE_PULL_REFRESH;tvTitle.setText("下拉刷新");ivArrow.setVisibility(View.VISIBLE);pbProgress.setVisibility(View.INVISIBLE);mHeaderView.setPadding(0, -mHeaderViewHeight, 0, 0);// 隐藏if (success) {tvTime.setText("最后刷新时间:" + getCurrentTime());}}}/*** 获取当前时间*/public String getCurrentTime() {SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");return format.format(new Date());}//定义个标记,要不然一直掉这个到底了,判断现在是否加载了private boolean isLoadingMore;@Overridepublic void onScrollStateChanged(AbsListView view, int scrollState) {if (scrollState == SCROLL_STATE_IDLE|| scrollState == SCROLL_STATE_FLING) {//空闲和快速滑状态if (getLastVisiblePosition() == getCount() - 1 && !isLoadingMore) {// 滑动到最后,默认是FALSE,然后置为TRUESystem.out.println("到底了.....");mFooterView.setPadding(0, 0, 0, 0);// 显示setSelection(getCount() - 1);// 改变listview显示位置isLoadingMore = true;//致为TRUE,下次进来不调用了,可是如果还有数据,什么时候致为FALSE了?在onRefreshComplete方法里,加载结束后if (mListener != null) {mListener.onLoadMore();// 在这里调用这个方法:加载下一页数据}}}}@Overridepublic void onScroll(AbsListView view, int firstVisibleItem,int visibleItemCount, int totalItemCount) {}OnItemClickListener mItemClickListener;@Overridepublic void setOnItemClickListener(//重写listview的setOnItemClickListener方法android.widget.AdapterView.OnItemClickListener listener) {super.setOnItemClickListener(this);//改成this,并且实现OnItemClickListener 接口mItemClickListener = listener;}@Overridepublic void onItemClick(AdapterView<?> parent, View view, int position,long id) {if (mItemClickListener != null) {//这样就调用地方的点击条目就变成了减去头view后重新开始的position了mItemClickListener.onItemClick(parent, view, position- getHeaderViewsCount(), id);}}}
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal" ><FrameLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:padding="10dp" ><ImageViewandroid:id="@+id/iv_arr"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:src="@drawable/common_listview_headview_red_arrow" /><ProgressBarandroid:id="@+id/pb_progress"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:indeterminateDrawable="@drawable/custom_progress"android:visibility="invisible" /></FrameLayout><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="match_parent"android:layout_gravity="center"android:gravity="center"android:orientation="vertical" ><TextViewandroid:id="@+id/tv_title"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="下拉刷新"android:textColor="#f00"android:textSize="16sp" /><TextViewandroid:id="@+id/tv_time"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="5dp"android:text="最后刷新时间:2015-03-10 17:07:07"android:textColor="@android:color/darker_gray"android:textSize="14sp" /></LinearLayout></LinearLayout>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"android:fromDegrees="0"android:pivotX="50%"android:pivotY="50%"android:toDegrees="360" ><shapeandroid:innerRadius="12dp"//圈内半径android:shape="ring"//圆环android:thickness="3dp"//圆圈厚度android:useLevel="false" ><gradientandroid:centerColor="#3f00"//开始,粉色,3是透明度android:endColor="#f00"//中间android:startColor="#fff" />//结束,循环转圈</shape></rotate>
<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" ><ProgressBarandroid:id="@+id/pb_pull_list_header"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:layout_margin="5dp"android:indeterminateDrawable="@drawable/custom_progress" /><TextViewandroid:id="@+id/tv_pull_list_header_title"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="加载中..."android:textColor="#ff0000"android:textSize="18sp" /></LinearLayout>
public class TabDetailPager extends BaseMenuDetailPager implementsOnPageChangeListener {。。。private String mMoreUrl;// 更多页面的地址,数据里有的话才加载下一页@Overridepublic View initViews() {View view = View.inflate(mActivity, R.layout.tab_detail_pager, null);// 加载头布局View headerView = View.inflate(mActivity, R.layout.list_header_topnews,null);ViewUtils.inject(this, view);ViewUtils.inject(this, headerView);// 将头条新闻以头布局的形式加给listviewlvList.addHeaderView(headerView);// 设置下拉刷新监听lvList.setOnRefreshListener(new OnRefreshListener() {@Overridepublic void onRefresh() {getDataFromServer();}@Overridepublic void onLoadMore() {if (mMoreUrl != null) {getMoreDataFromServer();//调用more接口} else {Toast.makeText(mActivity, "最后一页了", Toast.LENGTH_SHORT).show();// 收起加载更多的布局,传false和TRUE一样,只不过是是否更新更新时间的textviewlvList.onRefreshComplete(false);}}});lvList.setOnItemClickListener(new OnItemClickListener() {@Overridepublic void onItemClick(AdapterView<?> parent, View view,int position, long id) {System.out.println("被点击:" + position);// 35311,34221,34234,34342// 在本地记录已读状态String ids = PrefUtils.getString(mActivity, "read_ids", "");String readId = mNewsList.get(position).id;if (!ids.contains(readId)) {ids = ids + readId + ",";PrefUtils.setString(mActivity, "read_ids", ids);}// mNewsAdapter.notifyDataSetChanged();//这样写也可以,不过重新调用getview方法// 实现局部界面刷新, 这个view就是被点击的item布局对象,注意这是个好方法changeReadState(view);// 跳转新闻详情页Intent intent = new Intent();intent.setClass(mActivity, NewsDetailActivity.class);intent.putExtra("url", mNewsList.get(position).url);mActivity.startActivity(intent);}});return view;}/*** 改变已读新闻的颜色*/private void changeReadState(View view) {TextView tvTitle = (TextView) view.findViewById(R.id.tv_title);tvTitle.setTextColor(Color.GRAY);}@Overridepublic void initData() {String cache = CacheUtils.getCache(mUrl, mActivity);//读取缓存if (!TextUtils.isEmpty(cache)) {parseData(cache, false);}getDataFromServer();//不管用没有缓存都请求下服务器,看有没有最新的}private void getDataFromServer() {HttpUtils utils = new HttpUtils();utils.send(HttpMethod.GET, mUrl, new RequestCallBack<String>() {@Overridepublic void onSuccess(ResponseInfo<String> responseInfo) {String result = (String) responseInfo.result;System.out.println("页签详情页返回结果:" + result);parseData(result, false);lvList.onRefreshComplete(true);// 设置缓存CacheUtils.setCache(mUrl, result, mActivity);}@Overridepublic void onFailure(HttpException error, String msg) {Toast.makeText(mActivity, msg, Toast.LENGTH_SHORT).show();error.printStackTrace();lvList.onRefreshComplete(false)}});}/*** 加载下一页数据*/private void getMoreDataFromServer() {HttpUtils utils = new HttpUtils();utils.send(HttpMethod.GET, mMoreUrl, new RequestCallBack<String>() {@Overridepublic void onSuccess(ResponseInfo<String> responseInfo) {String result = (String) responseInfo.result;parseData(result, true);lvList.onRefreshComplete(true);}@Overridepublic void onFailure(HttpException error, String msg) {Toast.makeText(mActivity, msg, Toast.LENGTH_SHORT).show();error.printStackTrace();lvList.onRefreshComplete(false);}});}protected void parseData(String result, boolean isMore) {Gson gson = new Gson();mTabDetailData = gson.fromJson(result, TabData.class);System.out.println("页签详情解析:" + mTabDetailData);// 处理下一页链接String more = mTabDetailData.data.more;if (!TextUtils.isEmpty(more)) {mMoreUrl = GlobalContants.SERVER_URL + more;} else {mMoreUrl = null;}if (!isMore) {mTopNewsList = mTabDetailData.data.topnews;mNewsList = mTabDetailData.data.news;if (mTopNewsList != null) {mViewPager.setAdapter(new TopNewsAdapter());mIndicator.setViewPager(mViewPager);mIndicator.setSnap(true);// 支持快照显示mIndicator.setOnPageChangeListener(this);mIndicator.onPageSelected(0);// 让指示器重新定位到第一个点tvTitle.setText(mTopNewsList.get(0).title);}if (mNewsList != null) {mNewsAdapter = new NewsAdapter();lvList.setAdapter(mNewsAdapter);}// 自动轮播条显示if (mHandler == null) {mHandler = new Handler() {public void handleMessage(android.os.Message msg) {int currentItem = mViewPager.getCurrentItem();if (currentItem < mTopNewsList.size() - 1) {currentItem++;} else {currentItem = 0;}mViewPager.setCurrentItem(currentItem);// 切换到下一个页面// 继续延时3秒发消息,形成循环,可以handleMessage方法里发送消息的mHandler.sendEmptyMessageDelayed(0, 3000);};};mHandler.sendEmptyMessageDelayed(0, 3000);// 延时3秒后发消息}} else {// 如果是加载下一页,需要将数据追加给原来的集合ArrayList<TabNewsData> news = mTabDetailData.data.news;mNewsList.addAll(news);//这个方法将数据追加给原来的listmNewsAdapter.notifyDataSetChanged();}}/*** 头条新闻适配器** @author Kevin**/class TopNewsAdapter extends PagerAdapter {private BitmapUtils utils;public TopNewsAdapter() {utils = new BitmapUtils(mActivity);utils.configDefaultLoadingImage(R.drawable.topnews_item_default);// 设置默认图片}@Overridepublic int getCount() {return mTabDetailData.data.topnews.size();}@Overridepublic boolean isViewFromObject(View arg0, Object arg1) {return arg0 == arg1;}@Overridepublic Object instantiateItem(ViewGroup container, int position) {ImageView image = new ImageView(mActivity);image.setScaleType(ScaleType.FIT_XY);// 基于控件大小填充图片TopNewsData topNewsData = mTopNewsList.get(position);utils.display(image, topNewsData.topimage);// 传递imagView对象和图片地址container.addView(image);image.setOnTouchListener(new TopNewsTouchListener());//设置触摸监听return image;}@Overridepublic void destroyItem(ViewGroup container, int position, Object object) {container.removeView((View) object);}}/*** 头条新闻的触摸监听** @author Kevin**/class TopNewsTouchListener implements OnTouchListener {@Overridepublic boolean onTouch(View v, MotionEvent event) {switch (event.getAction()) {case MotionEvent.ACTION_DOWN:System.out.println("按下");// 删除Handler中的所有消息,Callbacks是说有个postDelayed,传的是Runnable,这么这个方法每几秒执行一次mHandler.removeCallbacksAndMessages(null);// mHandler.postDelayed(new Runnable() {//// @Override// public void run() {//// }// }, 3000);break;case MotionEvent.ACTION_CANCEL://因为当按下没抬起,而是滑了一下,那么事件就取消了,需要重新发送一下System.out.println("事件取消");mHandler.sendEmptyMessageDelayed(0, 3000);break;case MotionEvent.ACTION_UP:System.out.println("抬起");mHandler.sendEmptyMessageDelayed(0, 3000);break;default:break;}return true;}}/*** 新闻列表的适配器** @author Kevin**/class NewsAdapter extends BaseAdapter {private BitmapUtils utils;public NewsAdapter() {utils = new BitmapUtils(mActivity);utils.configDefaultLoadingImage(R.drawable.pic_item_list_default);}@Overridepublic int getCount() {return mNewsList.size();}@Overridepublic TabNewsData getItem(int position) {return mNewsList.get(position);}@Overridepublic long getItemId(int position) {return position;}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {ViewHolder holder;if (convertView == null) {convertView = View.inflate(mActivity, R.layout.list_news_item,null);holder = new ViewHolder();holder.ivPic = (ImageView) convertView.findViewById(R.id.iv_pic);holder.tvTitle = (TextView) convertView.findViewById(R.id.tv_title);holder.tvDate = (TextView) convertView.findViewById(R.id.tv_date);convertView.setTag(holder);} else {holder = (ViewHolder) convertView.getTag();}TabNewsData item = getItem(position);holder.tvTitle.setText(item.title);holder.tvDate.setText(item.pubdate);utils.display(holder.ivPic, item.listimage);String ids = PrefUtils.getString(mActivity, "read_ids", "");//保存缓存if (ids.contains(getItem(position).id)) {holder.tvTitle.setTextColor(Color.GRAY);} else {holder.tvTitle.setTextColor(Color.BLACK);}return convertView;}}static class ViewHolder {public TextView tvTitle;public TextView tvDate;public ImageView ivPic;}@Overridepublic void onPageScrollStateChanged(int arg0) {}@Overridepublic void onPageScrolled(int arg0, float arg1, int arg2) {}@Overridepublic void onPageSelected(int arg0) {TopNewsData topNewsData = mTopNewsList.get(arg0);tvTitle.setText(topNewsData.title);}}
标签:
原文地址:http://www.cnblogs.com/liuyu0529/p/4918951.html