网上很多这样的效果都是继承某个具体的AdapterView或ScrollView,这样很不通用,如果继承自一个ViewGroup(比如LinearLayout),那么任何放在其中的子view都有上拉下拉刷新,那不就完美了?
不废话,上代码:
- import android.content.Context;
- import android.util.AttributeSet;
- import android.view.LayoutInflater;
- import android.view.MotionEvent;
- import android.view.View;
- import android.view.ViewGroup;
- import android.view.animation.LinearInterpolator;
- import android.view.animation.RotateAnimation;
- import android.widget.AdapterView;
- import android.widget.ImageView;
- import android.widget.LinearLayout;
- import android.widget.ProgressBar;
- import android.widget.ScrollView;
- import android.widget.TextView;
- public class PullToRefreshView extends LinearLayout {
- // private static final String TAG = "PullToRefreshView";
- // refresh states
- private static final int PULL_TO_REFRESH = 2;
- private static final int RELEASE_TO_REFRESH = 3;
- private static final int REFRESHING = 4;
- // pull state
- private static final int PULL_UP_STATE = 0;
- private static final int PULL_DOWN_STATE = 1;
- /**
- * last y
- */
- private int mLastMotionY;
- /**
- * lock
- */
- // private boolean mLock;
- /**
- * header view
- */
- private View mHeaderView;
- /**
- * footer view
- */
- private View mFooterView;
- /**
- * list or grid
- */
- private AdapterView<?> mAdapterView;
- /**
- * scrollview
- */
- private ScrollView mScrollView;
- /**
- * header view height
- */
- private int mHeaderViewHeight;
- /**
- * footer view height
- */
- private int mFooterViewHeight;
- /**
- * header view image
- */
- private ImageView mHeaderImageView;
- /**
- * footer view image
- */
- private ImageView mFooterImageView;
- /**
- * header tip text
- */
- private TextView mHeaderTextView;
- /**
- * footer tip text
- */
- private TextView mFooterTextView;
- /**
- * header refresh time
- */
- private TextView mHeaderUpdateTextView;
- /**
- * footer refresh time
- */
- // private TextView mFooterUpdateTextView;
- /**
- * header progress bar
- */
- private ProgressBar mHeaderProgressBar;
- /**
- * footer progress bar
- */
- private ProgressBar mFooterProgressBar;
- /**
- * layout inflater
- */
- private LayoutInflater mInflater;
- /**
- * header view current state
- */
- private int mHeaderState;
- /**
- * footer view current state
- */
- private int mFooterState;
- /**
- * pull state,pull up or pull down;PULL_UP_STATE or PULL_DOWN_STATE
- */
- private int mPullState;
- /**
- * 变为向下的箭头,改变箭头方向
- */
- private RotateAnimation mFlipAnimation;
- /**
- * 变为逆向的箭头,旋转
- */
- private RotateAnimation mReverseFlipAnimation;
- /**
- * footer refresh listener
- */
- private OnFooterRefreshListener mOnFooterRefreshListener;
- /**
- * footer refresh listener
- */
- private OnHeaderRefreshListener mOnHeaderRefreshListener;
- /**
- * last update time
- */
- // private String mLastUpdateTime;
- public PullToRefreshView(Context context, AttributeSet attrs) {
- super(context, attrs);
- init();
- }
- public PullToRefreshView(Context context) {
- super(context);
- init();
- }
- /**
- * init
- *
- * @param context
- */
- private void init() {
- //需要设置成vertical
- setOrientation(LinearLayout.VERTICAL);
- // Load all of the animations we need in code rather than through XML
- mFlipAnimation = new RotateAnimation(0, -180,
- RotateAnimation.RELATIVE_TO_SELF, 0.5f,
- RotateAnimation.RELATIVE_TO_SELF, 0.5f);
- mFlipAnimation.setInterpolator(new LinearInterpolator());
- mFlipAnimation.setDuration(250);
- mFlipAnimation.setFillAfter(true);
- mReverseFlipAnimation = new RotateAnimation(-180, 0,
- RotateAnimation.RELATIVE_TO_SELF, 0.5f,
- RotateAnimation.RELATIVE_TO_SELF, 0.5f);
- mReverseFlipAnimation.setInterpolator(new LinearInterpolator());
- mReverseFlipAnimation.setDuration(250);
- mReverseFlipAnimation.setFillAfter(true);
- mInflater = LayoutInflater.from(getContext());
- // header view 在此添加,保证是第一个添加到linearlayout的最上端
- addHeaderView();
- }
- private void addHeaderView() {
- // header view
- mHeaderView = mInflater.inflate(R.layout.refresh_header, this, false);
- mHeaderImageView = (ImageView) mHeaderView
- .findViewById(R.id.pull_to_refresh_image);
- mHeaderTextView = (TextView) mHeaderView
- .findViewById(R.id.pull_to_refresh_text);
- mHeaderUpdateTextView = (TextView) mHeaderView
- .findViewById(R.id.pull_to_refresh_updated_at);
- mHeaderProgressBar = (ProgressBar) mHeaderView
- .findViewById(R.id.pull_to_refresh_progress);
- // header layout
- measureView(mHeaderView);
- mHeaderViewHeight = mHeaderView.getMeasuredHeight();
- LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT,
- mHeaderViewHeight);
- // 设置topMargin的值为负的header View高度,即将其隐藏在最上方
- params.topMargin = -(mHeaderViewHeight);
- // mHeaderView.setLayoutParams(params1);
- addView(mHeaderView, params);
- }
- private void addFooterView() {
- // footer view
- mFooterView = mInflater.inflate(R.layout.refresh_footer, this, false);
- mFooterImageView = (ImageView) mFooterView
- .findViewById(R.id.pull_to_load_image);
- mFooterTextView = (TextView) mFooterView
- .findViewById(R.id.pull_to_load_text);
- mFooterProgressBar = (ProgressBar) mFooterView
- .findViewById(R.id.pull_to_load_progress);
- // footer layout
- measureView(mFooterView);
- mFooterViewHeight = mFooterView.getMeasuredHeight();
- LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT,
- mFooterViewHeight);
- // int top = getHeight();
- // params.topMargin
- // =getHeight();//在这里getHeight()==0,但在onInterceptTouchEvent()方法里getHeight()已经有值了,不再是0;
- // getHeight()什么时候会赋值,稍候再研究一下
- // 由于是线性布局可以直接添加,只要AdapterView的高度是MATCH_PARENT,那么footer view就会被添加到最后,并隐藏
- addView(mFooterView, params);
- }
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
- // footer view 在此添加保证添加到linearlayout中的最后
- addFooterView();
- initContentAdapterView();
- }
- /**
- * init AdapterView like ListView,GridView and so on;or init ScrollView
- *
- */
- private void initContentAdapterView() {
- int count = getChildCount();
- if (count < 3) {
- throw new IllegalArgumentException(
- "This layout must contain 3 child views,and AdapterView or ScrollView must in the second position!");
- }
- View view = null;
- for (int i = 0; i < count - 1; ++i) {
- view = getChildAt(i);
- if (view instanceof AdapterView<?>) {
- mAdapterView = (AdapterView<?>) view;
- }
- if (view instanceof ScrollView) {
- // finish later
- mScrollView = (ScrollView) view;
- }
- }
- if (mAdapterView == null && mScrollView == null) {
- throw new IllegalArgumentException(
- "must contain a AdapterView or ScrollView in this layout!");
- }
- }
- private void measureView(View child) {
- ViewGroup.LayoutParams p = child.getLayoutParams();
- if (p == null) {
- p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
- ViewGroup.LayoutParams.WRAP_CONTENT);
- }
- int childWidthSpec = ViewGroup.getChildMeasureSpec(0, 0 + 0, p.width);
- int lpHeight = p.height;
- int childHeightSpec;
- if (lpHeight > 0) {
- childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight,
- MeasureSpec.EXACTLY);
- } else {
- childHeightSpec = MeasureSpec.makeMeasureSpec(0,
- MeasureSpec.UNSPECIFIED);
- }
- child.measure(childWidthSpec, childHeightSpec);
- }
- @Override
- public boolean onInterceptTouchEvent(MotionEvent e) {
- int y = (int) e.getRawY();
- switch (e.getAction()) {
- case MotionEvent.ACTION_DOWN:
- // 首先拦截down事件,记录y坐标
- mLastMotionY = y;
- break;
- case MotionEvent.ACTION_MOVE:
- // deltaY > 0 是向下运动,< 0是向上运动
- int deltaY = y - mLastMotionY;
- if (isRefreshViewScroll(deltaY)) {
- return true;
- }
- break;
- case MotionEvent.ACTION_UP:
- case MotionEvent.ACTION_CANCEL:
- break;
- }
- return false;
- }
- /*
- * 如果在onInterceptTouchEvent()方法中没有拦截(即onInterceptTouchEvent()方法中 return
- * false)则由PullToRefreshView 的子View来处理;否则由下面的方法来处理(即由PullToRefreshView自己来处理)
- */
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- // if (mLock) {
- // return true;
- // }
- int y = (int) event.getRawY();
- switch (event.getAction()) {
- case MotionEvent.ACTION_DOWN:
- // onInterceptTouchEvent已经记录
- // mLastMotionY = y;
- break;
- case MotionEvent.ACTION_MOVE:
- int deltaY = y - mLastMotionY;
- if (mPullState == PULL_DOWN_STATE) {//执行下拉
- headerPrepareToRefresh(deltaY);
- // setHeaderPadding(-mHeaderViewHeight);
- } else if (mPullState == PULL_UP_STATE) {//执行上拉
- footerPrepareToRefresh(deltaY);
- }
- mLastMotionY = y;
- break;
- case MotionEvent.ACTION_UP:
- case MotionEvent.ACTION_CANCEL:
- int topMargin = getHeaderTopMargin();
- if (mPullState == PULL_DOWN_STATE) {
- if (topMargin >= 0) {
- // 开始刷新
- headerRefreshing();
- } else {
- // 还没有执行刷新,重新隐藏
- setHeaderTopMargin(-mHeaderViewHeight);
- }
- } else if (mPullState == PULL_UP_STATE) {
- if (Math.abs(topMargin) >= mHeaderViewHeight
- + mFooterViewHeight) {
- // 开始执行footer 刷新
- footerRefreshing();
- } else {
- // 还没有执行刷新,重新隐藏
- setHeaderTopMargin(-mHeaderViewHeight);
- }
- }
- break;
- }
- return super.onTouchEvent(event);
- }
- /**
- * 是否应该到了父View,即PullToRefreshView滑动
- *
- * @param deltaY
- * , deltaY > 0 是向下运动,< 0是向上运动
- * @return
- */
- private boolean isRefreshViewScroll(int deltaY) {
- if (mHeaderState == REFRESHING || mFooterState == REFRESHING) {
- return false;
- }
- //对于ListView和GridView
- if (mAdapterView != null) {
- // 子view(ListView or GridView)滑动到最顶端
- if (deltaY > 0) {
- View child = mAdapterView.getChildAt(0);
- if (child == null) {
- // 如果mAdapterView中没有数据,不拦截
- return false;
- }
- if (mAdapterView.getFirstVisiblePosition() == 0
- && child.getTop() == 0) {
- mPullState = PULL_DOWN_STATE;
- return true;
- }
- int top = child.getTop();
- int padding = mAdapterView.getPaddingTop();
- if (mAdapterView.getFirstVisiblePosition() == 0
- && Math.abs(top - padding) <= 8) {//这里之前用3可以判断,但现在不行,还没找到原因
- mPullState = PULL_DOWN_STATE;
- return true;
- }
- } else if (deltaY < 0) {
- View lastChild = mAdapterView.getChildAt(mAdapterView
- .getChildCount() - 1);
- if (lastChild == null) {
- // 如果mAdapterView中没有数据,不拦截
- return false;
- }
- // 最后一个子view的Bottom小于父View的高度说明mAdapterView的数据没有填满父view,
- // 等于父View的高度说明mAdapterView已经滑动到最后
- if (lastChild.getBottom() <= getHeight()
- && mAdapterView.getLastVisiblePosition() == mAdapterView
- .getCount() - 1) {
- mPullState = PULL_UP_STATE;
- return true;
- }
- }
- }
- // 对于ScrollView
- if (mScrollView != null) {
- // 子scroll view滑动到最顶端
- View child = mScrollView.getChildAt(0);
- if (deltaY > 0 && mScrollView.getScrollY() == 0) {
- mPullState = PULL_DOWN_STATE;
- return true;
- } else if (deltaY < 0
- && child.getMeasuredHeight() <= getHeight()
- + mScrollView.getScrollY()) {
- mPullState = PULL_UP_STATE;
- return true;
- }
- }
- return false;
- }
- /**
- * header 准备刷新,手指移动过程,还没有释放
- *
- * @param deltaY
- * ,手指滑动的距离
- */
- private void headerPrepareToRefresh(int deltaY) {
- int newTopMargin = changingHeaderViewTopMargin(deltaY);
- // 当header view的topMargin>=0时,说明已经完全显示出来了,修改header view 的提示状态
- if (newTopMargin >= 0 && mHeaderState != RELEASE_TO_REFRESH) {
- mHeaderTextView.setText(R.string.pull_to_refresh_release_label);
- mHeaderUpdateTextView.setVisibility(View.VISIBLE);
- mHeaderImageView.clearAnimation();
- mHeaderImageView.startAnimation(mFlipAnimation);
- mHeaderState = RELEASE_TO_REFRESH;
- } else if (newTopMargin < 0 && newTopMargin > -mHeaderViewHeight) {// 拖动时没有释放
- mHeaderImageView.clearAnimation();
- mHeaderImageView.startAnimation(mFlipAnimation);
- // mHeaderImageView.
- mHeaderTextView.setText(R.string.pull_to_refresh_pull_label);
- mHeaderState = PULL_TO_REFRESH;
- }
- }
- /**
- * footer 准备刷新,手指移动过程,还没有释放 移动footer view高度同样和移动header view
- * 高度是一样,都是通过修改header view的topmargin的值来达到
- *
- * @param deltaY
- * ,手指滑动的距离
- */
- private void footerPrepareToRefresh(int deltaY) {
- int newTopMargin = changingHeaderViewTopMargin(deltaY);
- // 如果header view topMargin 的绝对值大于或等于header + footer 的高度
- // 说明footer view 完全显示出来了,修改footer view 的提示状态
- if (Math.abs(newTopMargin) >= (mHeaderViewHeight + mFooterViewHeight)
- && mFooterState != RELEASE_TO_REFRESH) {
- mFooterTextView
- .setText(R.string.pull_to_refresh_footer_release_label);
- mFooterImageView.clearAnimation();
- mFooterImageView.startAnimation(mFlipAnimation);
- mFooterState = RELEASE_TO_REFRESH;
- } else if (Math.abs(newTopMargin) < (mHeaderViewHeight + mFooterViewHeight)) {
- mFooterImageView.clearAnimation();
- mFooterImageView.startAnimation(mFlipAnimation);
- mFooterTextView.setText(R.string.pull_to_refresh_footer_pull_label);
- mFooterState = PULL_TO_REFRESH;
- }
- }
- /**
- * 修改Header view top margin的值
- *
- * @param deltaY
- */
- private int changingHeaderViewTopMargin(int deltaY) {
- LayoutParams params = (LayoutParams) mHeaderView.getLayoutParams();
- float newTopMargin = params.topMargin + deltaY * 0.3f;
- //这里对上拉做一下限制,因为当前上拉后然后不释放手指直接下拉,会把下拉刷新给触发了,感谢网友yufengzungzhe的指出
- //表示如果是在上拉后一段距离,然后直接下拉
- if(deltaY>0&&mPullState == PULL_UP_STATE&&Math.abs(params.topMargin) <= mHeaderViewHeight){
- return params.topMargin;
- }
- //同样地,对下拉做一下限制,避免出现跟上拉操作时一样的bug
- if(deltaY<0&&mPullState == PULL_DOWN_STATE&&Math.abs(params.topMargin)>=mHeaderViewHeight){
- return params.topMargin;
- }
- params.topMargin = (int) newTopMargin;
- mHeaderView.setLayoutParams(params);
- invalidate();
- return params.topMargin;
- }
- /**
- * header refreshing
- *
- */
- private void headerRefreshing() {
- mHeaderState = REFRESHING;
- setHeaderTopMargin(0);
- mHeaderImageView.setVisibility(View.GONE);
- mHeaderImageView.clearAnimation();
- mHeaderImageView.setImageDrawable(null);
- mHeaderProgressBar.setVisibility(View.VISIBLE);
- mHeaderTextView.setText(R.string.pull_to_refresh_refreshing_label);
- if (mOnHeaderRefreshListener != null) {
- mOnHeaderRefreshListener.onHeaderRefresh(this);
- }
- }
- /**
- * footer refreshing
- *
- */
- private void footerRefreshing() {
- mFooterState = REFRESHING;
- int top = mHeaderViewHeight + mFooterViewHeight;
- setHeaderTopMargin(-top);
- mFooterImageView.setVisibility(View.GONE);
- mFooterImageView.clearAnimation();
- mFooterImageView.setImageDrawable(null);
- mFooterProgressBar.setVisibility(View.VISIBLE);
- mFooterTextView
- .setText(R.string.pull_to_refresh_footer_refreshing_label);
- if (mOnFooterRefreshListener != null) {
- mOnFooterRefreshListener.onFooterRefresh(this);
- }
- }
- /**
- * 设置header view 的topMargin的值
- *
- * @param topMargin
- * ,为0时,说明header view 刚好完全显示出来; 为-mHeaderViewHeight时,说明完全隐藏了
- */
- private void setHeaderTopMargin(int topMargin) {
- LayoutParams params = (LayoutParams) mHeaderView.getLayoutParams();
- params.topMargin = topMargin;
- mHeaderView.setLayoutParams(params);
- invalidate();
- }
- /**
- * header view 完成更新后恢复初始状态
- *
- */
- public void onHeaderRefreshComplete() {
- setHeaderTopMargin(-mHeaderViewHeight);
- mHeaderImageView.setVisibility(View.VISIBLE);
- mHeaderImageView.setImageResource(R.drawable.ic_pulltorefresh_arrow);
- mHeaderTextView.setText(R.string.pull_to_refresh_pull_label);
- mHeaderProgressBar.setVisibility(View.GONE);
- // mHeaderUpdateTextView.setText("");
- mHeaderState = PULL_TO_REFRESH;
- }
- /**
- * Resets the list to a normal state after a refresh.
- *
- * @param lastUpdated
- * Last updated at.
- */
- public void onHeaderRefreshComplete(CharSequence lastUpdated) {
- setLastUpdated(lastUpdated);
- onHeaderRefreshComplete();
- }
- /**
- * footer view 完成更新后恢复初始状态
- */
- public void onFooterRefreshComplete() {
- setHeaderTopMargin(-mHeaderViewHeight);
- mFooterImageView.setVisibility(View.VISIBLE);
- mFooterImageView.setImageResource(R.drawable.ic_pulltorefresh_arrow_up);
- mFooterTextView.setText(R.string.pull_to_refresh_footer_pull_label);
- mFooterProgressBar.setVisibility(View.GONE);
- // mHeaderUpdateTextView.setText("");
- mFooterState = PULL_TO_REFRESH;
- }
- /**
- * Set a text to represent when the list was last updated.
- *
- * @param lastUpdated
- * Last updated at.
- */
- public void setLastUpdated(CharSequence lastUpdated) {
- if (lastUpdated != null) {
- mHeaderUpdateTextView.setVisibility(View.VISIBLE);
- mHeaderUpdateTextView.setText(lastUpdated);
- } else {
- mHeaderUpdateTextView.setVisibility(View.GONE);
- }
- }
- /**
- * 获取当前header view 的topMargin
- *
- */
- private int getHeaderTopMargin() {
- LayoutParams params = (LayoutParams) mHeaderView.getLayoutParams();
- return params.topMargin;
- }
- // /**
- // * lock
- // *
- // */
- // private void lock() {
- // mLock = true;
- // }
- //
- // /**
- // * unlock
- // *
- // */
- // private void unlock() {
- // mLock = false;
- // }
- /**
- * set headerRefreshListener
- *
- * @param headerRefreshListener
- */
- public void setOnHeaderRefreshListener(
- OnHeaderRefreshListener headerRefreshListener) {
- mOnHeaderRefreshListener = headerRefreshListener;
- }
- public void setOnFooterRefreshListener(
- OnFooterRefreshListener footerRefreshListener) {
- mOnFooterRefreshListener = footerRefreshListener;
- }
- /**
- * Interface definition for a callback to be invoked when list/grid footer
- * view should be refreshed.
- */
- public interface OnFooterRefreshListener {
- public void onFooterRefresh(PullToRefreshView view);
- }
- /**
- * Interface definition for a callback to be invoked when list/grid header
- * view should be refreshed.
- */
- public interface OnHeaderRefreshListener {
- public void onHeaderRefresh(PullToRefreshView view);
- }
- }
用法:
- import java.util.Date;
- import android.app.Activity;
- import android.os.Bundle;
- import android.widget.GridView;
- import com.example.pulltorefresh.PullToRefreshView.OnFooterRefreshListener;
- import com.example.pulltorefresh.PullToRefreshView.OnHeaderRefreshListener;
- public class TestGridView extends Activity implements OnHeaderRefreshListener,OnFooterRefreshListener{
- PullToRefreshView mPullToRefreshView;
- GridView mGridView;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.test_gridview);
- mPullToRefreshView = (PullToRefreshView)findViewById(R.id.main_pull_refresh_view);
- mGridView = (GridView)findViewById(R.id.gridview);
- mGridView.setAdapter(new DataAdapter(this));
- mPullToRefreshView.setOnHeaderRefreshListener(this);
- mPullToRefreshView.setOnFooterRefreshListener(this);
- mPullToRefreshView.setLastUpdated(new Date().toLocaleString());
- }
- @Override
- public void onFooterRefresh(PullToRefreshView view) {
- mPullToRefreshView.postDelayed(new Runnable() {
- @Override
- public void run() {
- mPullToRefreshView.onFooterRefreshComplete();
- }
- },1000);
- }
- @Override
- public void onHeaderRefresh(PullToRefreshView view) {
- mPullToRefreshView.postDelayed(new Runnable() {
- @Override
- public void run() {
- mPullToRefreshView.onHeaderRefreshComplete("更新于:"+new Date().toLocaleString());
- // mPullToRefreshView.onHeaderRefreshComplete();
- }
- },1000);
- }
- }
相关推荐
SwipeRefreshLayout作为父布局包裹ListView、GridView或ScrollView,提供下拉刷新的功能。当用户在顶部向下拖动时,SwipeRefreshLayout会显示一个刷新指示器,并触发刷新回调。开发者需要在这个回调中执行更新数据的...
5. "scrollview ListView GridView上拉刷新下拉加载":此项目可能包含在一个ScrollView容器内嵌套ListView和GridView的上拉刷新和下拉加载实现,这对于处理复杂布局的场景很有用。 6. "MyGridCustomDemo":这可能是...
总结来说,Android中的ScrollView、ListView和GridView上拉下拉刷新功能的实现涉及到自定义视图、滑动事件监听、数据加载逻辑和缓冲效果优化。熟练掌握这些技术,能有效提升应用的用户体验,使用户在浏览大量数据时...
`ZrcListView`是一个专门为Android平台设计的开源库,它提供了对ListView、GridView以及ScrollView的上拉下拉刷新支持。这个库的目标是简化开发过程,让开发者能够快速地为他们的应用添加这种用户体验。 在Android...
这个压缩包文件“安卓Android源码——下拉刷新控件(ListView好ScrollView版).rar”包含了实现这一功能的具体源代码,适用于ListView和ScrollView这两种常见的滚动视图。以下是对这个主题的详细讲解: 1. **下拉...
一个android上拉下拉刷新的基类,支持ListView,GridView和ScrollView的上拉下拉刷新,刷新效果不错。 是我从别的地方看到的,我把它搬了过来。 来自http://gundumw100.iteye.com/blog/1764763
这个“Android下拉刷新控件(ListView好ScrollView版)”压缩包文件包含的是关于如何在Android中实现这种功能的具体资料,主要集中在ListView和ScrollView这两种常见的滚动视图上。 1. **下拉刷新概念** 下拉刷新...
通过以上介绍,我们可以看到,尽管ListView、GridView和ScrollView在实现下拉刷新和上拉加载更多时有一些共通之处,但具体实现细节会因组件特性和需求不同而有所差异。理解这些组件的工作原理并掌握相应的库和技巧,...
下拉刷新 上拉更多 支持ListView GridView WebView svn地址:https://svn.stay4it.com/svn/opensource/branches/PullToRefresh同步的源码,用户名和密码我找不到了!
- 自定义View:由于ScrollView本身不支持直接添加下拉刷新功能,开发者通常需要自定义一个继承自ScrollView的类,添加额外的触摸事件处理,以检测用户的下拉动作。 - 使用第三方库:像PullToRefreshLayout这样的第...
当在一个ScrollView中嵌套一个ListView时,可能会遇到一些特定的问题,尤其是在实现下拉刷新功能时。本文将深入探讨这些问题及其解决方案。 ### 问题1:滑动冲突 由于ScrollView和ListView都具有滚动功能,它们之间...
本资源包"Android下拉刷新控件(ListView好ScrollView版).zip"提供了一个适用于ListView和ScrollView的下拉刷新解决方案,它使得这两种常见的滚动视图能够支持下拉刷新功能,从而增强用户界面的交互性和数据的实时...
在实际应用中,ListView和GridView通常配合Adapter使用,因此在实现下拉刷新和上拉加载更多时,可能需要更新Adapter的数据集,并通知Adapter数据已改变。同时,为了保持良好的用户体验,需要在加载数据过程中禁用...
SwipeRefreshLayout提供了一个下拉刷新的容器,内部可以嵌套ListView、GridView等,当用户下拉时,会显示刷新动画。PullToRefresh库则提供上拉加载更多功能,原理是监听滚动事件并在底部触发加载更多操作。 5. **...
Android下拉刷新控件(ListView好ScrollView版)-仅用于Android项目学习