现在的位置: 首页 > 综合 > 正文

Android自定义控件实战——仿新浪微博、QQ好友动态滑到底部自动加载

2018年05月27日 ⁄ 综合 ⁄ 共 3674字 ⁄ 字号 评论关闭

  转载请声明出处http://blog.csdn.net/zhongkejingwang/article/details/38963177  

前一篇已经把下拉刷新和上拉加载集成到一块了并且已经对所有View通用了,但是有时候需要的加载方式不是上拉,而是像新浪微博加载评论或QQ好友动态滑到ListView的底部时就自动加载了。所以在这篇文章里再介绍这种自动加载的实现,当然了,这个功能只针对ListView。如果仅仅是实现这样的自动加载,那就太简单了,也就判断是否滚动到底部而已,代码量很少,所以还加了下拉刷新,但在这里这两个功能是独立的,自动加载只是针对ListView进行的修改。

   效果图如下:

                    

下拉刷新的原理就不讲了,可以去看 Android通用版下拉刷新上拉加载控件,实现自动加载的思路就是:

在ListView后面增加一个FooterView,时刻监听ListView的滑动状态,当FooterView被滑到可见时,执行自动加载操作。

    但是这里需要注意的是手动滑到底和自由滚到底时的区别:

1、使劲滑的时候自由滚动在底部时会显示自动加载并执行加载回调

2、当用手慢慢滑动到底时,如果不松手,不会自动加载。

所以,基于这两个考虑,自然而然就需要覆写View的两个方法:onScrollChanged和onTouchEvent。

接下来就可以看代码了:

package com.jingchen.autoload;

import android.content.Context;
import android.graphics.drawable.AnimationDrawable;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;

/**
 * 如果不需要下拉刷新直接在canPullDown中返回false,这里的自动加载和下拉刷新没有冲突,通过增加在尾部的footerview实现自动加载,
 * 所以在使用中不要再动footerview了
 * 
 * @author chenjing
 * 
 */
public class PullableListView extends ListView implements Pullable
{
	public static final int INIT = 0;
	public static final int LOADING = 1;
	private OnLoadListener mOnLoadListener;
	private ImageView mLoadingView;
	private TextView mStateTextView;
	private int state = INIT;
	private boolean canLoad = true;
	private AnimationDrawable mLoadAnim;

	public PullableListView(Context context)
	{
		super(context);
		init(context);
	}

	public PullableListView(Context context, AttributeSet attrs)
	{
		super(context, attrs);
		init(context);
	}

	public PullableListView(Context context, AttributeSet attrs, int defStyle)
	{
		super(context, attrs, defStyle);
		init(context);
	}

	private void init(Context context)
	{
		View view = LayoutInflater.from(context).inflate(R.layout.load_more,
				null);
		mLoadingView = (ImageView) view.findViewById(R.id.loading_icon);
		mLoadingView.setBackgroundResource(R.anim.loading_anim);
		mLoadAnim = (AnimationDrawable) mLoadingView.getBackground();
		mStateTextView = (TextView) view.findViewById(R.id.loadstate_tv);
		addFooterView(view, null, false);
	}

	@Override
	public boolean onTouchEvent(MotionEvent ev)
	{
		switch (ev.getActionMasked())
		{
		case MotionEvent.ACTION_DOWN:
			// 按下的时候禁止自动加载
			canLoad = false;
			break;
		case MotionEvent.ACTION_UP:
			// 松开手判断是否自动加载
			canLoad = true;
			checkLoad();
			break;
		}
		return super.onTouchEvent(ev);
	}

	@Override
	protected void onScrollChanged(int l, int t, int oldl, int oldt)
	{
		super.onScrollChanged(l, t, oldl, oldt);
		// 在滚动中判断是否满足自动加载条件
		checkLoad();
	}

	/**
	 * 判断是否满足自动加载条件
	 */
	private void checkLoad()
	{
		if (reachBottom() && mOnLoadListener != null && state != LOADING
				&& canLoad)
		{
			mOnLoadListener.onLoad(this);
			changeState(LOADING);
		}
	}

	private void changeState(int state)
	{
		this.state = state;
		switch (state)
		{
		case INIT:
			mLoadAnim.stop();
			mLoadingView.setVisibility(View.INVISIBLE);
			mStateTextView.setText(R.string.more);
			break;

		case LOADING:
			mLoadingView.setVisibility(View.VISIBLE);
			mLoadAnim.start();
			mStateTextView.setText(R.string.loading);
			break;
		}
	}

	/**
	 * 完成加载
	 */
	public void finishLoading()
	{
		changeState(INIT);
	}

	@Override
	public boolean canPullDown()
	{
		if (getCount() == 0)
		{
			// 没有item的时候也可以下拉刷新
			return true;
		} else if (getFirstVisiblePosition() == 0
				&& getChildAt(0).getTop() >= 0)
		{
			// 滑到ListView的顶部了
			return true;
		} else
			return false;
	}

	public void setOnLoadListener(OnLoadListener listener)
	{
		this.mOnLoadListener = listener;
	}

	/**
	 * @return footerview可见时返回true,否则返回false
	 */
	public boolean reachBottom()
	{
		if (getCount() == 0)
		{
			// 没有item的时候也可以上拉加载
			return true;
		} else if (getLastVisiblePosition() == (getCount() - 1))
		{
			// 滑到底部了
			if (getChildAt(getLastVisiblePosition() - getFirstVisiblePosition()) != null
					&& getChildAt(
							getLastVisiblePosition()
									- getFirstVisiblePosition()).getTop() < getMeasuredHeight())
				return true;
		}
		return false;
	}

	public interface OnLoadListener
	{
		void onLoad(PullableListView pullableListView);
	}
}

Pullable接口是实现下拉刷新的,不用管。代码中判断滑动到底部是根据FooterView的上边缘距离ListView底部的距离。这个功能实现起来没什么难度,其他代码就不贴上来了,下面提供源码下载:

源码下载

抱歉!评论已关闭.