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

     
  • 相关阅读:
    DVWA 黑客攻防演练(十)反射型 XSS 攻击 Reflected Cross Site Scripting
    DVWA 黑客攻防演练(九) SQL 盲注 SQL Injection (Blind)
    DVWA 黑客攻防演练(八)SQL 注入 SQL Injection
    DVWA 黑客攻防演练(七)Weak Session IDs
    DVWA 黑客攻防演练(六)不安全的验证码 Insecure CAPTCHA
    DVWA 黑客攻防演练(五)文件上传漏洞 File Upload
    工作流表结构设计
    Visual Studio 2019尝鲜----新建空项目体验
    《使用CSLA 2019:CSLA .NET概述》原版和机译文档下载
    .NET快速开发平台的在线预览
  • 原文地址:https://www.cnblogs.com/AceIsSunshineRain/p/5193838.html
Copyright © 2011-2022 走看看