• android 之下拉刷新


    一.概述

    Android 下拉刷新几乎是每个应用都必带的功能, 并且现在下拉刷新第三方库也越来越多了,很方便就能实现该功能, 下面我介绍一下 自己常用的几个方法.

    二.例子

    第一种方式:就是集成ListView实现自定义控件完成上下拉刷新

    public class PullToRefreshListView extends ListView implements OnScrollListener, OnClickListener {
        /**
         * 下拉状态
         */
        private static final int PULL_TO_REFRESH = 1;   //下拉-默认为初始状态  准备下拉刷新
        private static final int RELEASE_TO_REFRESH = 2;   //释放刷新
        private static final int REFRESHING = 3;       //正在刷新
    
        private static final String TAG = "PullRefreshListView";
    
        private OnRefreshListener mOnRefreshListener;
    
        /**
         * 组件滑动监听器 scroll  当view在进行下拉滑动的时候,判断滑动的距离,
         * 如果达到可以进行刷新的临界点时候,回调当前接口中的方法
         * Listener that will receive notifications every time the list scrolls.
         */
        private OnScrollListener mOnScrollListener;
    
        //下拉刷新的的头部view
        private LinearLayout mRefreshView;
        private ImageView mRefreshViewImage;
        private ProgressBar mRefreshViewProgress;
        private TextView mRefreshViewText;
        private TextView mRefreshViewLastUpdated;
    
    
        private int mRefreshState;
        private int mCurrentScrollState;
    
        private RotateAnimation mFlipAnimation;
        private RotateAnimation mReverseFlipAnimation;
    
        private int mRefreshViewHeight;
        private int mRefreshOriginalTopPadding;
        private int mLastMotionY;
    
        public PullToRefreshListView(Context context) {
            super(context);
            init(context);
        }
    
        public PullToRefreshListView(Context context, AttributeSet attrs) {
            super(context, attrs);
            init(context);
        }
    
        private void init(Context context) {
            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);
    
            mRefreshView = (LinearLayout) View.inflate(context, R.layout.pull_to_refresh_header, null);
            mRefreshViewText = (TextView) mRefreshView.findViewById(R.id.pull_to_refresh_text);
            mRefreshViewImage = (ImageView) mRefreshView.findViewById(R.id.pull_to_refresh_image);
            mRefreshViewProgress = (ProgressBar) mRefreshView.findViewById(R.id.pull_to_refresh_progress);
            mRefreshViewLastUpdated = (TextView) mRefreshView.findViewById(R.id.pull_to_refresh_updated_at);
    
            mRefreshState = PULL_TO_REFRESH;
            mRefreshViewImage.setMinimumHeight(50); //设置下拉最小的高度为50
            
            setFadingEdgeLength(0);
            setHeaderDividersEnabled(false);
    
            //把refreshview加入到listview的头部
            addHeaderView(mRefreshView);
            super.setOnScrollListener(this);
            mRefreshView.setOnClickListener(this);
    
            mRefreshView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
            mRefreshViewHeight = mRefreshView.getMeasuredHeight();
            mRefreshOriginalTopPadding = -mRefreshViewHeight;
            
            resetHeaderPadding();
        }
    
        /**
         * Set the listener that will receive notifications every time the list scrolls.
         * 
         * @param l  The scroll listener.
         */
        @Override
        public void setOnScrollListener(OnScrollListener l) {
            mOnScrollListener = l;
        }
    
        /**
         * 注册listview下拉刷新回到接口
         * Register a callback to be invoked when this list should be refreshed.
         * 
         * @param onRefreshListener  The callback to run.
         */
        public void setOnRefreshListener(OnRefreshListener onRefreshListener) {
            mOnRefreshListener = onRefreshListener;
        }
    
         /**
          * 进行设置设置上一次更新的时候
          *
         * Set a text to represent when the list was last updated. 
         * @param lastUpdated Last updated at.
         */
        public void setLastUpdated(CharSequence lastUpdated) {
            if (lastUpdated != null) {
                mRefreshViewLastUpdated.setVisibility(View.VISIBLE);
                mRefreshViewLastUpdated.setText(lastUpdated);
            } else {
                mRefreshViewLastUpdated.setVisibility(View.GONE);
            }
        }
    
        /**
         * touch事件处理
         * @param event
         * @return
         */
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            final int y = (int) event.getY();
            switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mLastMotionY = y;
                break;
            case MotionEvent.ACTION_MOVE:
                int offsetY = (int) event.getY();
                int deltY = Math.round(offsetY - mLastMotionY);
                mLastMotionY = offsetY;
    
                if (getFirstVisiblePosition() == 0 && mRefreshState != REFRESHING) {
                    deltY = deltY / 2;
                    mRefreshOriginalTopPadding += deltY;
                    if (mRefreshOriginalTopPadding < -mRefreshViewHeight) {
                        mRefreshOriginalTopPadding = -mRefreshViewHeight;
                    }
                    resetHeaderPadding();
                }
                break;
            case MotionEvent.ACTION_UP:
                //当手指抬开得时候 进行判断下拉的距离 ,如果>=临界值,那么进行刷洗,否则回归原位
                if (!isVerticalScrollBarEnabled()) {
                    setVerticalScrollBarEnabled(true);
                }
                if (getFirstVisiblePosition() == 0 && mRefreshState != REFRESHING) {
                    if (mRefreshView.getBottom() >= mRefreshViewHeight 
                            && mRefreshState == RELEASE_TO_REFRESH) {
                        //准备开始刷新
                        prepareForRefresh();
                    } else {
                        // Abort refresh
                        resetHeader();
                    }
                }
                break;
            }
            return super.onTouchEvent(event);
        }
        
        @Override
        public void onScroll(AbsListView view, int firstVisibleItem,
                int visibleItemCount, int totalItemCount) {
            if (mCurrentScrollState == SCROLL_STATE_TOUCH_SCROLL && mRefreshState != REFRESHING) {
                 if (firstVisibleItem == 0) {
                    if ((mRefreshView.getBottom() >= mRefreshViewHeight)
                            && mRefreshState != RELEASE_TO_REFRESH) {
                        mRefreshViewText.setText(R.string.pull_to_refresh_release_label_it);
                        mRefreshViewImage.clearAnimation();
                        mRefreshViewImage.startAnimation(mFlipAnimation);
                        mRefreshState = RELEASE_TO_REFRESH;
                    } else if (mRefreshView.getBottom() < mRefreshViewHeight
                            && mRefreshState != PULL_TO_REFRESH) {
                        mRefreshViewText.setText(R.string.pull_to_refresh_pull_label_it);
                        mRefreshViewImage.clearAnimation();
                        mRefreshViewImage.startAnimation(mReverseFlipAnimation);
                        mRefreshState = PULL_TO_REFRESH;
                    }
                }
            }
            
            if (mOnScrollListener != null) {
                mOnScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);
            }
        }
    
        @Override
        public void onScrollStateChanged(AbsListView view, int scrollState) {
            mCurrentScrollState = scrollState;
            
            if (mOnScrollListener != null) {
                mOnScrollListener.onScrollStateChanged(view, scrollState);
            }
        }
    
        /**
         * Sets the header padding back to original size.
         */
        private void resetHeaderPadding() {
            mRefreshView.setPadding(
                    mRefreshView.getPaddingLeft(),
                    mRefreshOriginalTopPadding,
                    mRefreshView.getPaddingRight(),
                    mRefreshView.getPaddingBottom());
        }
    
        public void prepareForRefresh() {
            if (mRefreshState != REFRESHING) {
                mRefreshState = REFRESHING;
                
                mRefreshOriginalTopPadding = 0;
                resetHeaderPadding();
                
                mRefreshViewImage.clearAnimation();
                mRefreshViewImage.setVisibility(View.GONE);
                mRefreshViewProgress.setVisibility(View.VISIBLE);
                mRefreshViewText.setText(R.string.pull_to_refresh_refreshing_label_it);
                
                onRefresh();
            }
        }
    
        private void resetHeader() {
            mRefreshState = PULL_TO_REFRESH;
            
            mRefreshOriginalTopPadding = -mRefreshViewHeight;
            resetHeaderPadding();
            
            mRefreshViewImage.clearAnimation();
            mRefreshViewImage.setVisibility(View.VISIBLE);
            mRefreshViewProgress.setVisibility(View.GONE);
            mRefreshViewText.setText(R.string.pull_to_refresh_pull_label_it);
        }
    
        /**
         * 开始回调刷新
         */
        public void onRefresh() {
            Log.d(TAG, "onRefresh");
            if (mOnRefreshListener != null) {
                mOnRefreshListener.onRefresh();
            }
        }
        
        /**
         * Resets the list to a normal state after a refresh.
         */
        public void onRefreshComplete() {        
            Log.d(TAG, "onRefreshComplete");
    
            resetHeader();
        }
        
        @Override
        public void onClick(View v) {
            Log.d(TAG, "onClick");
        }
        
        /**
         * Interface definition for a callback to be invoked when list should be
         * refreshed.
         */
        public interface OnRefreshListener {
            /**
             * Called when the list should be refreshed.
             * <p>
             * A call to {@link PullToRefreshListView #onRefreshComplete()} is
             * expected to indicate that the refresh has completed.
             */
            public void onRefresh();
        }
    }

    上面代码就完成了,上下拉刷新工作, 直接拷贝到工程无需任何修改就可使用

    当然它还需一个"头布局"

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/pull_to_refresh_header"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:background="#F3F3F3"
        android:orientation="vertical" >
        <RelativeLayout
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:paddingTop="23dip" >
            <LinearLayout
                android:id="@+id/pull_to_refresh_view"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerHorizontal="true"
                android:orientation="vertical" >
                <TextView
                    android:id="@+id/pull_to_refresh_text"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="center"
                    android:gravity="center"
                    android:text="@string/pull_to_refresh_pull_label"
                    android:textColor="#777777"
                    android:textSize="16sp" />
                <TextView
                    android:id="@+id/pull_to_refresh_updated_at"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="center"
                    android:gravity="center"
                    android:text="@string/pull_to_refresh_updated_at"
                    android:textColor="#999999"
                    android:textSize="14sp" />
            </LinearLayout>
            <ProgressBar
                android:id="@+id/pull_to_refresh_progress"
                android:layout_width="30dip"
                android:layout_height="30dip"
                android:layout_marginRight="22dip"
                android:layout_marginTop="5dip"
                android:layout_toLeftOf="@+id/pull_to_refresh_view"
                android:indeterminate="true"
                android:indeterminateDrawable="@anim/ic_loading_refresh"
                android:visibility="gone" />
            <ImageView
                android:id="@+id/pull_to_refresh_image"
                android:layout_width="32dip"
                android:layout_height="32dip"
                android:layout_marginRight="20dip"
                android:layout_marginTop="5dip"
                android:layout_toLeftOf="@+id/pull_to_refresh_view"
                android:contentDescription="@string/app_name"
                android:gravity="center"
                android:src="@drawable/ic_refresh_down" />
        </RelativeLayout>
        <View
            android:layout_width="fill_parent"
            android:layout_height="15dip" />
    </LinearLayout>

    此外代码中还用到了 时间的工具类: 如下

    public class SharedPreferencesHelper {
        private static final String SHARED_PATH = "fda_shared";
        private static SharedPreferencesHelper instance;
        private SharedPreferences sp;
        private SharedPreferences.Editor editor;
    
        public static SharedPreferencesHelper getInstance(Context context) {
            if (instance == null && context != null) {
                instance = new SharedPreferencesHelper(context);
            }
            return instance;
        }
    
        private SharedPreferencesHelper(Context context) {
            sp = context.getSharedPreferences(SHARED_PATH, Context.MODE_PRIVATE);
            editor = sp.edit();
        }
    
        public long getLongValue(String key) {
            if (key != null && !key.equals("")) {
                return sp.getLong(key, 0);
            }
            return 0;
        }
    
        public String getStringValue(String key) {
            if (key != null && !key.equals("")) {
                return sp.getString(key, null);
            }
            return null;
        }
    
        public int getIntValue(String key) {
            if (key != null && !key.equals("")) {
                return sp.getInt(key, 0);
            }
            return 0;
        }
    
        public int getIntValueByDefault(String key)
        {
            if (key != null && !key.equals("")) {
                return sp.getInt(key, 0);
            }
            return 0;
        }
        public boolean getBooleanValue(String key) {
            if (key != null && !key.equals("")) {
                return sp.getBoolean(key, false);
            }
            return true;
        }
    
        public float getFloatValue(String key) {
            if (key != null && !key.equals("")) {
                return sp.getFloat(key, 0);
            }
            return 0;
        }
    
        public void putStringValue(String key, String value) {
            if (key != null && !key.equals("")) {
                editor = sp.edit();
                editor.putString(key, value);
                editor.commit();
            }
        }
    
        public void putIntValue(String key, int value) {
            if (key != null && !key.equals("")) {
                editor = sp.edit();
                editor.putInt(key, value);
                editor.commit();
            }
        }
    
        public void putBooleanValue(String key, boolean value) {
            if (key != null && !key.equals("")) {
                editor = sp.edit();
                editor.putBoolean(key, value);
                editor.commit();
            }
        }
    
        public void putLongValue(String key, long value) {
            if (key != null && !key.equals("")) {
                editor = sp.edit();
                editor.putLong(key, value);
                editor.commit();
            }
        }
    
        public void putFloatValue(String key, Float value) {
            if (key != null && !key.equals("")) {
                editor = sp.edit();
                editor.putFloat(key, value);
                editor.commit();
            }
        }
    }
    public class SharedPreferencesTag {
        public static final String DEMO_KEY="demo_key";
    
    }
    public class UIUtils {
    
        /**
         * 设置上次更新数据时间
         * @param listView
         * @param key key表示具体某个列表
         */
        public static void setPullToRefreshLastUpdated(PullToRefreshListView listView, String key,Context pContext) {
            SharedPreferencesHelper spHelper = SharedPreferencesHelper.getInstance(pContext);
            long lastUpdateTimeStamp = spHelper.getLongValue(key);
            listView.setLastUpdated(getUpdateTimeString(lastUpdateTimeStamp));
        }
    
        /**
         * 保存更新数据时间
         * @param listView
         * @param key key表示具体某个列表
         */
        public static void savePullToRefreshLastUpdateAt(PullToRefreshListView listView, String key,Context pContext) {
            listView.onRefreshComplete();
            SharedPreferencesHelper spHelper = SharedPreferencesHelper.getInstance(pContext);
            long lastUpdateTimeStamp=System.currentTimeMillis();
            spHelper.putLongValue(key, lastUpdateTimeStamp);
            listView.setLastUpdated(getUpdateTimeString(lastUpdateTimeStamp));
        }
    
        /**
         * 更新时间字符串
         * @param timestamp
         * @return
         */
        @SuppressLint("SimpleDateFormat")
        public static String getUpdateTimeString(long timestamp) {
            if (timestamp <= 0) {
                return "上次更新时间:";
            } else {
                String textDate = "上次更新时间:";
                Calendar now = Calendar.getInstance();
                Calendar c = Calendar.getInstance();
                c.setTimeInMillis(timestamp);
                if (c.get(Calendar.YEAR) == now.get(Calendar.YEAR)
                        && c.get(Calendar.MONTH) == now.get(Calendar.MONTH)
                        && c.get(Calendar.DATE) == now.get(Calendar.DATE)) {
                    SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
                    return textDate += sdf.format(c.getTime());
                } else if (c.get(Calendar.YEAR) == now.get(Calendar.YEAR)) {
                    SimpleDateFormat sdf = new SimpleDateFormat("MM/dd HH:mm");
                    return textDate += sdf.format(c.getTime());
                } else {
                    SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm");
                    return textDate += sdf.format(c.getTime());
                }
            }
        }
    }

    这样就完成了, 测试效果图

    源码地址:https://yunpan.cn/cryrD4r7PIgWb (提取码:fcb1)

    --------------------------------------------------------------------------------------------------------

    如果觉得上面的写法太麻烦,或者根本就不想自己写代码,那就用第三方库吧,PullToRefresh

    使用步骤:

    1. https://github.com/cardview/Android-PullToRefresh 下载源码

    2. 解压下载文件, 把library 作为Module导入 Android studio

    3. 把该library 最为库,引入 自己工程中

    引用文章:http://blog.csdn.net/hantangsongming/article/details/42490277

    --------------------------------------------------------------------------------------------------------

    谷歌也推出了一种下拉刷新方式:

    SwipeRefreshLayout ,但是它只支持下拉刷新,并不支持 上拉加载更多

    public class MainActivity extends AppCompatActivity {
        private RecyclerView demo_recycler;
        private LinearLayoutManager linearLayoutManager;
        private RefreshRecyclerAdpater adapter;
        private SwipeRefreshLayout demo_swiperefreshlayout;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            demo_recycler=(RecyclerView)this.findViewById(R.id.demo_recycler);
            linearLayoutManager=new LinearLayoutManager(this);
            linearLayoutManager.setOrientation(OrientationHelper.VERTICAL);
            demo_recycler.setLayoutManager(linearLayoutManager);
            demo_recycler.setAdapter(adapter = new RefreshRecyclerAdpater(this));
    
            demo_swiperefreshlayout=(SwipeRefreshLayout)this.findViewById(R.id.demo_swiperefreshlayout);
         //这是设置圆圈背景色---白色 demo_swiperefreshlayout.setProgressBackgroundColorSchemeColor(getResources().getColor(android.R.color.white));
         //设置进度条颜色,最多可以设置4种,每转一圈变换一种颜色 demo_swiperefreshlayout.setColorSchemeResources(android.R.color.holo_blue_light, android.R.color.holo_green_light, android.R.color.holo_red_light, android.R.color.holo_orange_light);
    //设置圆圈距离顶部距离 demo_swiperefreshlayout.setProgressViewOffset(
    false, 0, 50);
         //模拟联网获取数据 demo_swiperefreshlayout.setOnRefreshListener(
    new SwipeRefreshLayout.OnRefreshListener() { @Override public void onRefresh() { new Handler().postDelayed(new Runnable() { @Override public void run() { List<String> temp=new ArrayList<String>(); for(int i=0;i<5;i++){ temp.add("refresh item "+i); } adapter.addItem(temp); if(demo_swiperefreshlayout.isRefreshing()) { demo_swiperefreshlayout.setRefreshing(false); } } },5000); Toast.makeText(MainActivity.this,"下拉刷新",Toast.LENGTH_SHORT).show(); } }); } }

    对应的RecyclerView 的adapter

    public class RefreshRecyclerAdpater extends RecyclerView.Adapter<RefreshRecyclerAdpater.ViewHolder>{
        private LayoutInflater mInflater;
        private List<String> mTitles=null;
        public RefreshRecyclerAdpater(Context context){
            this.mInflater=LayoutInflater.from(context);
            this.mTitles=new ArrayList<String>();
            for (int i=0;i<20;i++){
                int index=i+1;
                mTitles.add("item"+index);
            }
        }
        /**
         * item显示类型
         * @param parent
         * @param viewType
         * @return
         */
        @Override
        public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            final View view=mInflater.inflate(R.layout.item_recycler_layout,parent,false);
            //这边可以做一些属性设置,甚至事件监听绑定
            //view.setBackgroundColor(Color.RED);
            ViewHolder viewHolder=new ViewHolder(view);
    
            return viewHolder;
        }
    
        /**
         * 数据的绑定显示
         * @param holder
         * @param position
         */
        @Override
        public void onBindViewHolder(ViewHolder holder, int position) {
            holder.item_tv.setText(mTitles.get(position));
            holder.itemView.setTag(position);
        }
        @Override
        public int getItemCount() {
            return mTitles.size();
        }
    
        //自定义的ViewHolder,持有每个Item的的所有界面元素
        public static class ViewHolder extends RecyclerView.ViewHolder {
            public TextView item_tv;
            public ViewHolder(View view){
                super(view);
                item_tv = (TextView)view.findViewById(R.id.item_tv);
            }
        }
    
        //添加数据
        /**
         * 添加最新数据
         * @param newDatas
         */
        public void addItem(List<String> newDatas) {
            newDatas.addAll(mTitles);
            mTitles.removeAll(mTitles);
            mTitles.addAll(newDatas);
            notifyDataSetChanged();
        }
    
    }

    布局文件:

    <?xml version="1.0" encoding="utf-8"?>
    <android.support.v4.widget.SwipeRefreshLayout
        android:id="@+id/demo_swiperefreshlayout"
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scrollbars="vertical">
        <android.support.v7.widget.RecyclerView
            android:id="@+id/demo_recycler"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            >
        </android.support.v7.widget.RecyclerView>
    
    </android.support.v4.widget.SwipeRefreshLayout>
  • 相关阅读:
    飞腾2000+上面银河麒麟v10 安装virt-manager创建虚拟机的操作过程
    postgresql重置序列起始值
    行为链分析zipkin
    Elasticsearch冷热分离原理和实践
    Window 各个版本对应的版本号大全
    为何fdisk和df 输出的信息不一致?
    Java使用ConcurrentHashMap实现简单的内存式缓存
    Linux系统中如何查找大文件或文件夹的方法
    Class.newInstance()与Constructor.newInstance()创建对象
    Wazuh完整性监测和命令监测注册表并邮件告警
  • 原文地址:https://www.cnblogs.com/android-zcq/p/5135859.html
Copyright © 2020-2023  润新知