[安卓]新闻客户端(六) 主页面之slidingMenu & fragment(4)

下拉菜单的实现:基本原理是把一些东西隐藏起来,下来时才显示,要设置一个padding属性,负值表示往里面收,也就是隐藏,然后在初始化数据时需要记录位置信息

只有dy小于0,并且listview显示的是第一个item时,才刷新数据

底部自动加载的实现:不能再new adapter,这样之前的数据就没有了,而是应该通知adapter


主要原理为监听触摸和滑动操作,在listview头部加载一个视图。那要做的其实很简单:

1.写好加载到listview头部的view 

2.重写listview,实现onTouchEvent方法和onScroll方法,监听滑动状态。

3.计算headview全部显示出来即可实行加载动作,加载完成即刷新列表。

4.重新隐藏headview


第一步:下拉刷新和自动加载,本质上都是对listview的重加载,所以可以写到一个类里面RefreshListView,来实现重加载时对listview的初始化,之前TabDetailPager里的listview的声明什么的都要改成RefreshListView了



public class RefreshListView extends ListView {

	public RefreshListView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		// TODO Auto-generated constructor stub
	}

	public RefreshListView(Context context, AttributeSet attrs) {
		super(context, attrs);
		// TODO Auto-generated constructor stub
	}

	public RefreshListView(Context context) {
		super(context);
		// TODO Auto-generated constructor stub
	}

}

出了一个bug,忘了改布局里的类型,不是listview了

<?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:orientation="vertical" >
    <com.example.mynewsapp.view.RefreshListView
        android:layout_width="fill_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:cacheColorHint="#FFF"
        android:id="@+id/lv_tab_detail_news"/>
</LinearLayout>


下拉刷新的时候,等于是把隐藏的view给显示出来,他有3个状态,没要拉到指定位置时显示下拉刷新,拉到底显示释放刷新,释放后,显示正在刷新,整个过程中都要显示上次刷新时间,如图


他应该有一个单独布局,这其中有一个不显示进度条的圆形进度条,需要在drawable里利用动画,rotate的shape节点定义其属性

<?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">
        <gradient
            android:centerColor="#3f00"
            android:endColor="#f00"
            android:startColor="#fff" />
    </shape>
</rotate>

<?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="horizontal" >
    <FrameLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="10dp" >
        <ImageView
            android:id="@+id/iv_refreshhead_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_refreshhead_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_refreshhead_title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="下拉刷新"
            android:textColor="#f00"
            android:textSize="16sp" />
        <TextView
            android:id="@+id/tv_refreshhead_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>

第二步:需要一个callback,当发生下拉或者到底时,能够调用两个方法刷新  关于callback,这里讲的很透彻 

http://www.cnblogs.com/codingmyworld/archive/2011/07/22/2113514.html

这个callback此处就应该是监听了

注意一个语法问题,接口即默认是抽象,无需再添上abstract了(普通的方法加abstract表明这个必须要被实现,接口里的方法默认必须全部实现)

//注册
	public void setOnRefreshListner(onRefreshListener listener){	
		 mlistener= listener;
	}	
	//callback
	public interface onRefreshListener{	
		public void onRefesh();
		public void onLoadmore();
	}

这两个方法的具体该怎么操作在tab里完成,回头再说


关于下拉刷新


关于自动刷新


public class RefreshListView extends ListView {
	private int mHeaderViewHeight;
	int rawstartY ;
	int rawendY ;
	private View mHeaderView;
	private ImageView iv_refreshhead_arr;
	private ProgressBar pb_refreshhead_progress;
	private TextView tv_refreshhead_title;
	private TextView tv_refreshhead_time;
	
	private static final int STATE_PULL_REFRESH = 0;// 下拉刷新
	private static final int STATE_RELEASE_REFRESH = 1;// 松开刷新
	private static final int STATE_REFRESHING = 2;// 正在刷新
	private int mCurrrentState = STATE_PULL_REFRESH;// 当前状态
	
	private View mFooterView;
	private int mFooterViewHeight;
	
	onRefreshListener mlistener;
	public RefreshListView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		// TODO Auto-generated constructor stub
		initHeaderView();
		initFooterView();
	}

	public RefreshListView(Context context, AttributeSet attrs) {
		super(context, attrs);
		// TODO Auto-generated constructor stub
		initHeaderView();
		initFooterView();
	}

	public RefreshListView(Context context) {
		super(context);
		// TODO Auto-generated constructor stub
		initHeaderView();
		initFooterView();
	}
	private void initHeaderView() {
		mHeaderView = View.inflate(getContext(), R.layout.refresh_header, null);
		//下拉时,实际上是往list的顶部加一个view
		this.addHeaderView(mHeaderView);
		
		mHeaderView.measure(0, 0);//测量控件高度,0,0为默认参数
		mHeaderViewHeight = mHeaderView.getMeasuredHeight();
		mHeaderView.setPadding(0, -mHeaderViewHeight, 0, 0);// 隐藏头布局

		iv_refreshhead_arr = (ImageView)mHeaderView.findViewById(R.id.iv_refreshhead_arr);
		pb_refreshhead_progress = (ProgressBar) mHeaderView.findViewById(R.id.pb_refreshhead_progress);
		tv_refreshhead_title = (TextView) mHeaderView.findViewById(R.id.tv_refreshhead_title);
		tv_refreshhead_time = (TextView) mHeaderView.findViewById(R.id.tv_refreshhead_time);					
	}	
	@Override
	public boolean onTouchEvent(MotionEvent ev) {
		switch (ev.getAction()) {
		case MotionEvent.ACTION_DOWN:
			 rawstartY = (int) ev.getRawY();
			break;
		case MotionEvent.ACTION_MOVE:		
			if (rawstartY == -1) {// 确保startY有效
				rawstartY = (int) ev.getRawY();
			}
			rawendY = (int) ev.getRawY();
			int dy = rawendY-rawstartY;		
			System.out.println("RefreshListView.onTouchEvent()"+dy+":"+getFirstVisiblePosition());
			if (dy>0 &&  getFirstVisiblePosition()==0) {
				int padding =  dy-mHeaderViewHeight  ;       //-(mHeaderViewHeight-dy);
				System.out.println("RefreshListView.onTouchEvent() setPadding"+padding);
				if (mCurrrentState==STATE_REFRESHING) {//如果发现正在刷新的时候,就不做判断
					break;
				}			
				mHeaderView.setPadding(0, padding, 0, 0);		
				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;//设置完之后需要return,已消费。避免其他事件处理			
			}
			break;
		case MotionEvent.ACTION_UP:
			rawstartY = -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:
			tv_refreshhead_title.setText("下拉刷新");
			iv_refreshhead_arr.setVisibility(View.VISIBLE);
            pb_refreshhead_progress.setVisibility(View.INVISIBLE);
			break;
		case STATE_RELEASE_REFRESH:
			tv_refreshhead_title.setText("释放刷新");
			iv_refreshhead_arr.setVisibility(View.VISIBLE);
            pb_refreshhead_progress.setVisibility(View.INVISIBLE);
			break;
		case STATE_REFRESHING:
			tv_refreshhead_title.setText("正在刷新");
			iv_refreshhead_arr.setVisibility(View.INVISIBLE);
            pb_refreshhead_progress.setVisibility(View.VISIBLE);
            if (mlistener!=null) {
				mlistener.onRefesh();
			}
			break;
		default:
			break;
		}					
	}
	public String getCurrentTime() {
		SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		String time = format.format(new Date());	
		return time ;
	}
	
	
	
	private void initFooterView() {
        mFooterView = View.inflate(getContext(), R.layout.refresh_listview_footer, null);	
		this.addFooterView(mFooterView); //加到listview的最后面	
		mFooterView.measure(0, 0);
		mFooterViewHeight = mFooterView.getMeasuredHeight();
		mFooterView.setPadding(0, -mFooterViewHeight, 0, 0);// 隐藏脚布局		
		this.setOnScrollListener(new MyOnScrollListener());		
	}
	private boolean isLoadingMore = false;
	class MyOnScrollListener implements OnScrollListener{
		@Override
		public void onScrollStateChanged(AbsListView view, int scrollState) {
			// TODO Auto-generated method stub
			if((scrollState== SCROLL_STATE_IDLE ||scrollState== SCROLL_STATE_FLING )&& !isLoadingMore){
				if (getLastVisiblePosition()==getCount()-1) {//滑动到最后的位置						
					System.out
							.println("RefreshListView.MyOnScrollListener.onScrollStateChanged() 到底部了");
					mFooterView.setPadding(0, 0, 0, 0);// 显示
					setSelection(getCount()-1);
					isLoadingMore=true;				
					if (mlistener!=null) {
						mlistener.onLoadmore();
					}
				}			
			}
		}
		@Override
		public void onScroll(AbsListView view, int firstVisibleItem,
				int visibleItemCount, int totalItemCount) {
			// TODO Auto-generated method stub
		}				
	}
	public void onRefreshComplete() {
		if (isLoadingMore) {
			mFooterView.setPadding(0, -mFooterViewHeight, 0, 0);// 隐藏
			isLoadingMore=false;
		}else {
			mCurrrentState = STATE_PULL_REFRESH;
			tv_refreshhead_title.setText("下拉刷新");
			iv_refreshhead_arr.setVisibility(View.VISIBLE);
			pb_refreshhead_progress.setVisibility(View.INVISIBLE);
			mHeaderView.setPadding(0, -mHeaderViewHeight, 0, 0);// 隐藏
		}		
	}
	
	
	//注册
	public void setOnRefreshListner(onRefreshListener listener){	
		 mlistener= listener;
	}	
	//callback
	public interface onRefreshListener{	
		public void onRefesh();
		public void onLoadmore();
	}
}


tab里的调用

     lv_tab_detail_news.setOnRefreshListner(new onRefreshListener() {
			@Override
			public void onRefesh() {
				// TODO Auto-generated method stub
				getDataFromServer();
			}

			@Override
			public void onLoadmore() {
				if (mMoreUrl!=null) {
	 				getMoreDataFromServer();
				}
				else {
					Toast.makeText(mActivity, "没有更多新闻了,休息一下", 0).show();
					lv_tab_detail_news.onRefreshComplete();
				}
			}
		});
        //返回整个listview	
      	return v;
	}
    protected 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;
				System.out.println("获取到的json数据" + result);
				parseData(result, true);
				lv_tab_detail_news.onRefreshComplete();
			}			
			@Override
			public void onFailure(HttpException error, String msg) {
				Toast.makeText(mActivity, msg, Toast.LENGTH_SHORT).show();
				error.printStackTrace();
				lv_tab_detail_news.onRefreshComplete();			 
			}
		});
	}

 注意获取数据时要调用complete 

 lv_tab_detail_news.setOnRefreshListner(new onRefreshListener() {
			@Override
			public void onRefesh() {
				// TODO Auto-generated method stub
				getDataFromServer();
			}

			@Override
			public void onLoadmore() {
				if (mMoreUrl!=null) {
	 				getMoreDataFromServer();
				}
				else {
					Toast.makeText(mActivity, "没有更多新闻了,休息一下", 0).show();
					lv_tab_detail_news.onRefreshComplete();
				}
			}
		});
        //返回整个listview	
      	return v;
	}
    protected 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;
				System.out.println("获取到的json数据" + result);
				parseData(result, true);
				lv_tab_detail_news.onRefreshComplete();
			}			
			@Override
			public void onFailure(HttpException error, String msg) {
				Toast.makeText(mActivity, msg, Toast.LENGTH_SHORT).show();
				error.printStackTrace();
				lv_tab_detail_news.onRefreshComplete();			 
			}
		});
	}
	@Override
	public void initData() {
		//初始化数据获取服务器的数据
		super.initData();
		getDataFromServer();
	}
	private void getDataFromServer() {
		// TODO Auto-generated method stub
		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("获取到的json数据" + result);
				parseData(result, false);
				//下拉刷新要complete
				lv_tab_detail_news.onRefreshComplete();
			}	
			@Override
			public void onFailure(HttpException error, String msg) {
				Toast.makeText(mActivity, msg, Toast.LENGTH_SHORT).show();
				error.printStackTrace();
				lv_tab_detail_news.onRefreshComplete();
			}
		});
	}
	
	private void parseData(String result, boolean isLoadMoredata) {
		// 拿到数据后,开始解析
		Gson gson = new Gson();
		mTabDetailData = gson.fromJson(result, TabData.class);
		//下拉需要新的URL
		mMoreUrl =  mTabDetailData.data.more;
		if (TextUtils.isEmpty(mMoreUrl) ) {
			mMoreUrl=null;
		}else {
			mMoreUrl =  GlobalContants.SERVER_URL+mTabDetailData.data.more;
		}
		System.out.println(" 解析到的数据为:" + mTabDetailData);
		
		if (!isLoadMoredata) {
			mTopNewsList = mTabDetailData.data.topnews;
			
			vp_tab_detail_topnews.setAdapter(new TopNewsAdapter());
			vp_tab_detail_topnews.setOnPageChangeListener(new MyOnPageChangeListener());
		    //indicator的显示
			topnews_indicator.setViewPager(vp_tab_detail_topnews);
			topnews_indicator.setOnPageChangeListener(new MyOnPageChangeListener());
			topnews_indicator.setSnap(true);
			
		    //拿到数据之后,现将第一个topnews的title设置到控件上。即默认显示第一条topnews
			String tilte0 = mTopNewsList.get(0).title;
			tv_tabdetial_topnewstitle.setText(tilte0);
			
			//下面的listview也要设置adapter去填充数据		
			listnewsData =mTabDetailData.data.news;
			MyListViewAdapter listViewAdapter = new MyListViewAdapter();
			lv_tab_detail_news.setAdapter(listViewAdapter);
		}else {//如果是loadmore,需要先拿到数据,然后将数据追加给之前的list		
			 ArrayList<TabNewsData>  morenews =mTabDetailData.data.news;
			 listnewsData.addAll(morenews);
			 listViewAdapter.notifyDataSetChanged();
		}
	}


一个小bug,空指针,在上面声明了adapter,下面又声明了,这就相当于new了一个新的,去掉下面的类型声明

//下面的listview也要设置adapter去填充数据		
			listnewsData =mTabDetailData.data.news;
			listViewAdapter = new MyListViewAdapter();
			lv_tab_detail_news.setAdapter(listViewAdapter);

OK~

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值