首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >10.下拉刷新、加载更多、标记已读、轮播条、缓存

10.下拉刷新、加载更多、标记已读、轮播条、缓存

作者头像
六月的雨
发布2018-05-14 10:57:58
1.1K0
发布2018-05-14 10:57:58
举报

下拉刷新、加载更多、标记已读、轮播条、缓存

下拉刷新-------

1.addHeaderView必须在setAdapter之前调用

2.将paddingTop设置一个headerView高度的负值去隐藏它

getHeight()和getMeasuredHeight()的区别:

getMeasuredHeight():获取测量完的高度,只要在onMeasure方法执行完,就可以用

                   它获取到宽高,在自定义控件内部多使用这个

使用view.measure(0,0)方法可以主动通知系统去测量,然后就

可以直接使用它获取宽高

getHeight():必须在onLayout方法执行完后,才能获得宽高

view.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {

@Override

public void onGlobalLayout() {

headerView.getViewTreeObserver().removeGlobalOnLayoutListener(this);

int headerViewHeight = headerView.getHeight();

//直接可以获取宽高

}

});

3.setSelection(position);将对应位置的item放置到屏幕顶端

下拉刷新的原理:

1.自定义带下拉刷新,加载更多的listview

/*
* 提示:该行代码过长,系统自动注释不进行高亮。一键复制会移除系统注释 
* 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接口	}	@Override	public 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;// 计算padding				mHeaderView.setPadding(0, padding, 0, 0);// 设置当前padding				if (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;	@Override	public void onScrollStateChanged(AbsListView view, int scrollState) {		if (scrollState == SCROLL_STATE_IDLE				|| scrollState == SCROLL_STATE_FLING) {//空闲和快速滑状态			if (getLastVisiblePosition() == getCount() - 1 && !isLoadingMore) {// 滑动到最后,默认是FALSE,然后置为TRUE				System.out.println("到底了.....");				mFooterView.setPadding(0, 0, 0, 0);// 显示				setSelection(getCount() - 1);// 改变listview显示位置				isLoadingMore = true;//致为TRUE,下次进来不调用了,可是如果还有数据,什么时候致为FALSE了?在onRefreshComplete方法里,加载结束后				if (mListener != null) {					mListener.onLoadMore();// 在这里调用这个方法:加载下一页数据				}			}		}	}	@Override	public void onScroll(AbsListView view, int firstVisibleItem,			int visibleItemCount, int totalItemCount) {	}	OnItemClickListener mItemClickListener;	@Override	public void setOnItemClickListener(//重写listview的setOnItemClickListener方法			android.widget.AdapterView.OnItemClickListener listener) {		super.setOnItemClickListener(this);//改成this,并且实现OnItemClickListener 接口		mItemClickListener = listener;	}	@Override	public void onItemClick(AdapterView<?> parent, View view, int position,			long id) {		if (mItemClickListener != null) {//这样就调用地方的点击条目就变成了减去头view后重新开始的position了			mItemClickListener.onItemClick(parent, view, position					- getHeaderViewsCount(), id);		}	}}
*/

2.头布局

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="wrap_content"    android:orientation="horizontal" >    <FrameLayout        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:padding="10dp" >        <ImageView            android: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" />        <ProgressBar            android: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>    <LinearLayout        android:layout_width="wrap_content"        android:layout_height="match_parent"        android:layout_gravity="center"        android:gravity="center"        android:orientation="vertical" >        <TextView            android:id="@+id/tv_title"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:text="下拉刷新"            android:textColor="#f00"            android:textSize="16sp" />        <TextView            android: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>

custom_progress:改变ProgressBar的样子,这里在drawable里自定义了一个圆圈

<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" >        <gradient            android:centerColor="#3f00"//开始,粉色,3是透明度            android:endColor="#f00"//中间            android:startColor="#fff" />//结束,循环转圈    </shape></rotate>

3.脚布局

<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: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" />    <TextView        android: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>

4.在页签详情页中调用自定义listview的方法

public class TabDetailPager extends BaseMenuDetailPager implements		OnPageChangeListener {	。。。	private String mMoreUrl;// 更多页面的地址,数据里有的话才加载下一页
	@Override	public 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);		// 将头条新闻以头布局的形式加给listview		lvList.addHeaderView(headerView);		// 设置下拉刷新监听		lvList.setOnRefreshListener(new OnRefreshListener() {			@Override			public void onRefresh() {				getDataFromServer();			}			@Override			public void onLoadMore() {				if (mMoreUrl != null) {					getMoreDataFromServer();//调用more接口				} else {					Toast.makeText(mActivity, "最后一页了", Toast.LENGTH_SHORT)							.show();// 收起加载更多的布局,传false和TRUE一样,只不过是是否更新更新时间的textview
					lvList.onRefreshComplete(false);				}			}		});		lvList.setOnItemClickListener(new OnItemClickListener() {			@Override			public 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);	}	@Override	public 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>() {			@Override			public 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);			}			@Override			public 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>() {			@Override			public void onSuccess(ResponseInfo<String> responseInfo) {				String result = (String) responseInfo.result;				parseData(result, true);				lvList.onRefreshComplete(true);			}			@Override			public 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);//这个方法将数据追加给原来的list			mNewsAdapter.notifyDataSetChanged();		}	}	/**	 * 头条新闻适配器	 * 	 * @author Kevin	 * 	 */	class TopNewsAdapter extends PagerAdapter {		private BitmapUtils utils;		public TopNewsAdapter() {			utils = new BitmapUtils(mActivity);			utils.configDefaultLoadingImage(R.drawable.topnews_item_default);// 设置默认图片		}		@Override		public int getCount() {			return mTabDetailData.data.topnews.size();		}		@Override		public boolean isViewFromObject(View arg0, Object arg1) {			return arg0 == arg1;		}		@Override		public 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;		}		@Override		public void destroyItem(ViewGroup container, int position, Object object) {			container.removeView((View) object);		}	}	/**	 * 头条新闻的触摸监听	 * 	 * @author Kevin	 * 	 */	class TopNewsTouchListener implements OnTouchListener {		@Override		public 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);		}		@Override		public int getCount() {			return mNewsList.size();		}		@Override		public TabNewsData getItem(int position) {			return mNewsList.get(position);		}		@Override		public long getItemId(int position) {			return position;		}		@Override		public 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;	}	@Override	public void onPageScrollStateChanged(int arg0) {	}	@Override	public void onPageScrolled(int arg0, float arg1, int arg2) {	}	@Override	public void onPageSelected(int arg0) {		TopNewsData topNewsData = mTopNewsList.get(arg0);		tvTitle.setText(topNewsData.title);	}}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2015-10-28 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档