zoukankan      html  css  js  c++  java
  • 偷懒了一天,去给人装系统去了~ 今天继续更 自己敲代码实现下拉刷新上滑加载更多

    "你会装系统吗?""会""我电脑打不开了""好我马上到"....然后就是从WIN7开始装 装完直接装WIN10 然后装软件...然后..........妹子为什么不能自己学学装系统呢......

     

    下拉刷新的原理很简单,下拉刷新也是listview的头布局 只不过靠setPadding(0,-PaddingTop,0,0),让他隐藏在头部局上面(这么说只是为了更形象,其实是头部的一条缝)  

     

    下拉刷新的原理就是这样. 下面来敲代码 自定义我们的refreshListView

    第一步  先实现我们的下拉刷新这几个字 

    网上下的后台资源 JSON数据有点旧 不过这不是重点,第一步 我们给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="wrap_content"
        android:orientation="horizontal" >
    
        <FrameLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:paddingBottom="10dp"
            android:paddingLeft="10dp"
            android:paddingTop="10dp" >
    
            <ImageView
                android:id="@+id/iv_arrow"
                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_loading"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:visibility="invisible"
                android:indeterminateDrawable="@drawable/custom_progress" />
        </FrameLayout>
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            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="17sp" />
    
            <TextView
                android:id="@+id/tv_time"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="5dp"
                android:text="2016-02-16 22:01"
                android:textColor="#9e9e9e"
                android:textSize="15sp" />
        </LinearLayout>
    
    </LinearLayout>

    自带progressbar的太丑了简单自定义了一个 旋转动画和渐变效果  我设置

    android:visibility="invisible"

     刷新ing的时候再设置可见.

    custom_progress

     

    <?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="15dp"
            android:shape="ring"
            android:thickness="3dp"
            android:useLevel="false" >
            <gradient
                android:centerColor="#5f00"
                android:endColor="#fff"
                android:startColor="#f00"
                android:type="sweep" />
        </shape>
    
    </rotate>

    2 这一步我们要他隐藏:

    那么 我们在我们的RefreshListView中先拿到头布局的高度 并把它隐藏:

    /**
    * 初始化头布局
    */
    private void initHeaderView() {
    mHeaderView = View.inflate(getContext(), R.layout.list_refrsh_header,
            null);
    this.addHeaderView(mHeaderView);// 添加头布局
    
    // 隐藏头布局(1, 获取头布局高度, 2.设置负paddingTop,布局就会往上走)
    // int height = mHeaderView.getHeight();//此处无法获取高度,因为布局还没有绘制完成
    // 绘制之前就要获取布局高度
    mHeaderView.measure(0, 0);// 手动测量布局
    mHeaderViewHeight = mHeaderView.getMeasuredHeight();// 测量之后的高度
    // 隐藏头布局
    mHeaderView.setPadding(0, -mHeaderViewHeight, 0, 0);
    
    tvTitle = (TextView) mHeaderView.findViewById(R.id.tv_title);
    ivArrow = (ImageView) mHeaderView.findViewById(R.id.iv_arrow);
    pbLoading = (ProgressBar) mHeaderView.findViewById(R.id.pb_loading);
    tvTime = (TextView) mHeaderView.findViewById(R.id.tv_time);
    
    
    }
    View Code

    3 这样就看不到了. 那么下部我们应该把它拉出来, 通过获得手指在Y轴上的移动距离dy , 当dy-mHeaderViewHeight > 0  且是第一个可见条目的id == 0 那么 头布局可见

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
        case MotionEvent.ACTION_DOWN:
            startY = (int) ev.getY();
            break;
        case MotionEvent.ACTION_MOVE:
            if (startY == -1) {// 如果用户按住头条新闻向下滑动, 会导致listview无法拿到ACTION_DOWN,
                                // 此时要重新获取startY
                startY = (int) ev.getY();
            }
    
            // 如果当前正在刷新, 什么都不做了
            if (mCurrentState == STATE_REFRESHING) {
                break;
            }
    
            int endY = (int) ev.getY();
            int dy = endY - startY;
    
            if (dy > 0 && getFirstVisiblePosition() == 0) {// 向下滑动&当前显示的是第一个item,才允许下拉刷新
                int paddingTop = dy - mHeaderViewHeight;// 计算当前的paddingtop值
    
                // 根据padding切换状态
                if (paddingTop >= 0
                        && mCurrentState != STATE_RELEASE_TO_REFRESH) {
                    // 切换到松开刷新
                    mCurrentState = STATE_RELEASE_TO_REFRESH;
                    refreshState();
                } else if (paddingTop < 0
                        && mCurrentState != STATE_PULL_TO_REFRESH) {
                    // 切换到下拉刷新
                    mCurrentState = STATE_PULL_TO_REFRESH;
                    refreshState();
                }
    
                mHeaderView.setPadding(0, paddingTop, 0, 0);// 重新设置头布局padding
                return true;
            }
    
            break;
        case MotionEvent.ACTION_UP:
            startY = -1;// 起始坐标归零
    
            if (mCurrentState == STATE_RELEASE_TO_REFRESH) {
                // 如果当前是松开刷新, 就要切换为正在刷新
                mCurrentState = STATE_REFRESHING;
                // 显示头布局
                mHeaderView.setPadding(0, 0, 0, 0);
                
                refreshState();
    
    //            // 下拉刷新回调
    //            if (mListener != null) {
    //                mListener.onRefresh();
    //            }
    
            } else if (mCurrentState == STATE_PULL_TO_REFRESH) {
                // 隐藏头布局
                mHeaderView.setPadding(0, -mHeaderViewHeight, 0, 0);
            }
    
            break;
    
        default:
            break;
        }
    
        return super.onTouchEvent(ev);
    }
    
    /**
     * 初始化箭头动画
     */
    private void initAnim() {
        animUp = new RotateAnimation(0, -180, Animation.RELATIVE_TO_SELF, 0.5f,
                Animation.RELATIVE_TO_SELF, 0.5f);
        animUp.setDuration(500);
        animUp.setFillAfter(true);// 保持状态
    
        animDown = new RotateAnimation(-180, 0, Animation.RELATIVE_TO_SELF,
                0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
        animDown.setDuration(500);
        animDown.setFillAfter(true);// 保持状态
    }
    
    
    /**
     * 根据当前状态刷新界面
     */
    private void refreshState() {
        switch (mCurrentState) {
        case STATE_PULL_TO_REFRESH:
            tvTitle.setText("下拉刷新");
            // 箭头向下移动
            ivArrow.startAnimation(animDown);
            // 隐藏进度条
            pbLoading.setVisibility(View.INVISIBLE);
            ivArrow.setVisibility(View.VISIBLE);
            break;
        case STATE_RELEASE_TO_REFRESH:
            tvTitle.setText("松开刷新");
            // 箭头向上移动
            ivArrow.startAnimation(animUp);
            // 隐藏进度条
            pbLoading.setVisibility(View.INVISIBLE);
            ivArrow.setVisibility(View.VISIBLE);
            break;
        case STATE_REFRESHING:
            tvTitle.setText("正在刷新...");
            pbLoading.setVisibility(View.VISIBLE);
            ivArrow.clearAnimation();// 必须清除动画,才能隐藏控件
            ivArrow.setVisibility(View.INVISIBLE);
            break;
    
        default:
            break;
        }
    }

    4 我们暂时完成了下拉刷新 是不是有点激动! 原理居然这么简单!说白了就是个paddingTop再加入状态判断和设置.

    但是我们现在的下拉刷新不会回去. 那么我们来实现它回去的逻辑 ,下拉刷新接口回调刷新数据后会返回成功或者失败 ,那么 我们创建一个方法

    onRefreshComplete

    来通知listview 是成功还是失败然后做相应的UI操作

    /**
         * 从服务器获取数据
         */
        private void getDataFromSevice() {
            HttpUtils httpUtils = new HttpUtils();
    
            httpUtils.send(HttpMethod.GET, mUrl, new RequestCallBack<String>() {
    
                @Override
                public void onSuccess(ResponseInfo<String> responseInfo) {
                    // 请求成功调用
                    String result = responseInfo.result;// 获得json字符串
    
                    processResult(result);
                    CacheUtils.setCache(mUrl, result, mActivity);
                    mListView.onRefreshComplete(true);
                }
    
                @Override
                public void onFailure(HttpException error, String msg) {
                    // 请求失败调用
                    error.printStackTrace();
                    Toast.makeText(mActivity, msg, Toast.LENGTH_LONG).show();
                    mListView.onRefreshComplete(false);
                }
            });
        }

    RefreshListView: 不管成功还是失败都隐藏掉

    // 刷新完成
    public void onRefreshComplete(boolean success) {
        if (success) {
            // 隐藏头布局
            mHeaderView.setPadding(0, -mHeaderViewHeight, 0, 0);
            mCurrentState = STATE_PULL_TO_REFRESH;
            // 隐藏进度条
            pbLoading.setVisibility(View.INVISIBLE);
            ivArrow.setVisibility(View.VISIBLE);
            tvTitle.setText("下拉刷新");
                setCurrentTime();
        
        }else{
            // 隐藏头布局
            mHeaderView.setPadding(0, -mHeaderViewHeight, 0, 0);
            mCurrentState = STATE_PULL_TO_REFRESH;
            // 隐藏进度条
            pbLoading.setVisibility(View.INVISIBLE);
            ivArrow.setVisibility(View.VISIBLE);
            tvTitle.setText("下拉刷新");
            Toast.makeText(getContext(), "刷新失败请检查网络连接", Toast.LENGTH_LONG).show();
        }
    }

    现在是这样 我把tomcat服务器关了:

    5 继续. 上滑加载更多: 原理 添加listview脚布局 然后通过设置-paddingTop隐藏掉

    跟下拉过程一样 只不过回调的链接不一样 上拉加载更多的链接一般是more : "/10007/list_2.json"这样的     需要重新解析more的json数据

    首先 新建一个脚布局:

    很简单 一个ProgressBar 和一个TextView

    <?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:gravity="center"
        android:orientation="horizontal" >
    
        <ProgressBar
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:indeterminateDrawable="@drawable/custom_progress" />
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="5dp"
            android:text="加载中..."
            android:textColor="#f00"
            android:textSize="17sp" />
    
    </LinearLayout>

     设置给我们的 RefreshListView

    /**
     * 初始化脚布局
     */
    private void initFooterView() {
        mFooterView = View.inflate(getContext(), R.layout.list_refresh_footer,
                null);
        this.addFooterView(mFooterView);
    
        mFooterView.measure(0, 0);
        mFooterViewHeight = mFooterView.getMeasuredHeight();
    
       
    }

    好 大概就这样了.

    6 隐藏它 并设置监听 当listview是可见的最后一个条目的时候显示并加载更多

    /**
     * 初始化脚布局
     */
    private void initFooterView() {
        mFooterView = View.inflate(getContext(), R.layout.list_refresh_footer,
                null);
        this.addFooterView(mFooterView);
    
        mFooterView.measure(0, 0);
        mFooterViewHeight = mFooterView.getMeasuredHeight();
    
        // 隐藏脚布局
        mFooterView.setPadding(0, -mFooterViewHeight, 0, 0);
    
        // 设置滑动监听
        this.setOnScrollListener(this);
    }

    监听是否是listview可见的最后一个条目,然后通过接口的回调 来实现加载更多的方法

    声明一个全局变量 private boolean isLoadingMore;// 来标记是否正在加载更多

        @Override
        public void onScrollStateChanged(AbsListView view, int scrollState) {
            if (scrollState == SCROLL_STATE_IDLE) {
                int lastVisiblePosition = getLastVisiblePosition();// 当前界面显示的最后一个item的位置
                if (lastVisiblePosition >= getCount() - 1 && !isLoadingMore) {
                    isLoadingMore = true;
                    // System.out.println("到底了");
                    // 加载更多了....(到底了)
                    // 显示脚布局
                    mFooterView.setPadding(0, 0, 0, 0);
                    // listview设置当前要展示的item的位置
                    setSelection(getCount() - 1);// 跳到加载更多item的位置去展示
    
                    if (mListener != null) {
                        mListener.loadMore();
                    }
                }
            }
        }

     7 然后再新闻界面页签页面  重写接口的 loadMore方法 并判断more的Url是否为空

            // 设置下拉刷新监听
            lvList.setOnRefreshListener(new OnRefreshListener() {
    
                @Override
                public void onRefresh() {
                    // 从网络加载数据
                    getDataFromServer();
                }
    
                @Override
                public void loadMore() {
                    // 加载更多数据
                    if (mMoreUrl != null) {
                        System.out.println("加载下一页数据...");
                        getMoreDataFromServer();
                    } else {
                        lvList.onRefreshComplete(true);// 收起加载更多布局
                        Toast.makeText(mActivity, "没有更多数据了", Toast.LENGTH_SHORT)
                                .show();
                    }
                }
            });

    8 新建 getMoreDataFromServer();  来请求more的数据

    /**
         * 加载更多数据
         */
        protected void getMoreDataFromServer() {
            HttpUtils utils = new HttpUtils();
            utils.send(HttpMethod.GET, mMoreUrl, new RequestCallBack<String>() {
    
                @Override
                public void onSuccess(ResponseInfo<String> responseInfo) {
                    String result = responseInfo.result;
                    processResult(result, true);
                    // 收起加载更多布局
                    mListView.onRefreshComplete(true);
                }
    
                @Override
                public void onFailure(HttpException error, String msg) {
                    error.printStackTrace();
                    Toast.makeText(mActivity, msg, Toast.LENGTH_SHORT).show();
                    // 收起加载更多布局
                    mListView.onRefreshComplete(false);
                }
            });
        }


    9 然后新建一个boolean 用来判断是是否是ismore 不是的话就是普通的加载

        protected void processResult(String result, Boolean isMore) {
    
            Gson gson = new Gson();
            NewsDatas mNewsDatas = gson.fromJson(result, NewsDatas.class);
            if (!TextUtils.isEmpty(mNewsDatas.data.more) ) {
                // 初始化地址
                mMoreUrl = Contants.SERVER_URL + mNewsDatas.data.more;
            } else {
                // 没有下一页了
                mMoreUrl = null;
            }
            
            if (!isMore) {
                // 获取头条新闻数据
                mTopNewsList = mNewsDatas.data.topnews;
    
                if (mTopNewsList != null) {
                    mTopNewsAdapter = new TopNewsAdapter();
    
                    mViewPager.setAdapter(mTopNewsAdapter);
                    // 给页面指示器设置Viewpager
                    mCirclePageIndicator.setViewPager(mViewPager);//将指示器和viewpager绑定
                    mCirclePageIndicator.setSnap(true);
                    // 给mCirclePageIndicator 设置监听
                    mCirclePageIndicator.setOnPageChangeListener(new OnPageChangeListener() {
    
                        @Override
                        public void onPageSelected(int position) {
                            // TODO Auto-generated method stub
                            String title = mTopNewsList.get(position).title;
                            topNewsTitle.setText(title);
                        }
    
                        @Override
                        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
                            // TODO Auto-generated method stub
    
                        }
    
                        @Override
                        public void onPageScrollStateChanged(int state) {
                            // TODO Auto-generated method stub
    
                        }
                    });
    
                    mCirclePageIndicator.onPageSelected(0);// 将小圆点位置归零,
                                                            // 解决它会在页面销毁时仍记录上次位置的bug
                    topNewsTitle.setText(mTopNewsList.get(0).title);// 初始化第一页标题
                }
    
                // 初始化新闻列表
                newsListViewData = mNewsDatas.data.news;
    //            System.out.println("新闻列表数据:" + newsListViewData);
                if (newsListViewData != null) {
                    newsListViewDataAdapter = new MyListViewAdapter();
                    mListView.setAdapter(newsListViewDataAdapter);
                }
            }
            else {
                // 加载更多
                            ArrayList<News> moreData = mNewsDatas.data.news;
                            newsListViewData.addAll(moreData);// 追加数据
                            newsListViewDataAdapter.notifyDataSetChanged();// 刷新listview
            }
    
        }

    10 重写刷新完成的方法 区分隐藏头布局还是 脚布局
        // 刷新完成
        public void onRefreshComplete(boolean success) {
            if (!isLoadingMore) {
                // 隐藏头布局
                mHeaderView.setPadding(0, -mHeaderViewHeight, 0, 0);
                mCurrentState = STATE_PULL_TO_REFRESH;
                // 隐藏进度条
                pbLoading.setVisibility(View.INVISIBLE);
                ivArrow.setVisibility(View.VISIBLE);
                tvTitle.setText("下拉刷新");
                // 刷新失败,不需要更新时间
                if (success) {
                    setCurrentTime();
                }
            } else {
                // 隐藏脚布局
                mFooterView.setPadding(0, -mFooterViewHeight, 0, 0);
                isLoadingMore = false;
            }
        }

    最终效果:  标题带2的是刷新出来的

    项目地址

    https://github.com/AceInAndroid/AnYangNews

     
  • 相关阅读:
    安装MYSQL8.0提示api-ms-win-crt-runtime-l1-1-0.dll 丢失
    【.net】未在本地计算机上注册“microsoft.ACE.oledb.12.0”提供程序解决办法
    Windows 2008 R2 配置 DNS 实现二级域名
    如何修改windows Server 2012 远程桌面连接默认端口
    System x 服务器制作ServerGuide U盘安装Windows Server 2012 R2操作系统
    MYSQL安装后自带用户的作用
    mysql 查看数据库、表的基本命令
    嵌入式必知基础算法
    嵌入式学习网站集合
    C避坑指南
  • 原文地址:https://www.cnblogs.com/AceIsSunshineRain/p/5193838.html
Copyright © 2011-2022 走看看