RecyclerView下拉刷新和载入很多其它
之前一直写的是ListVIew下拉刷新,可是好多朋友都说要RecycleView的下拉刷新和滑动载入。事实上,这个原理都是几乎相同。抽出时间,我就写了下RecycleView的下拉刷新和滑动载入很多其它。因此,这才写到博客里,记录一下。
在大家阅读这篇博客前。大家须要了解的知识
事件是以ACTION_DOWN開始到ACTION_UP货ACTION_CANCEL结束的一个序列,期间事件分发,能够通过onInterceptTouchEvent方法和dispatchTouchEvent进行事件的阻止和消费。
比方怎样加入一个Decoration.
当RecyclerView滑动到了最顶部,则能够触发下拉事件;当RecyclerView滑动到了底部,则能够触发滑动载入很多其它的事件。然后在通过事件分发。进行滑动事件的处理。
- package com.mjc.recyclerviewdemo.refresh;
- import android.content.Context;
- import android.graphics.Color;
- import android.support.v7.widget.LinearLayoutManager;
- import android.support.v7.widget.RecyclerView;
- import android.util.AttributeSet;
- import android.util.Log;
- import android.view.MotionEvent;
- import android.view.ViewConfiguration;
- import android.widget.LinearLayout;
- import android.widget.Scroller;
- import com.mjc.recyclerviewdemo.CustomItemDecoration;
- /**
- * Created by mjc on 2016/3/11.
- */
- public class PullToRefreshRecycleView extends LinearLayout {
- //头部
- private IHeaderView mHeaderView;
- private int mHeaderHeight;
- //尾部
- private CustomFooterView mFooterView;
- private int mFooterHeight;
- //阻尼系数,越大,阻力越大
- public static final float RATIO = 0.5f;
- //当前是否阻止事件
- private boolean isIntercept;
- //是否正在刷新
- private boolean isRefreshing;
- //滑动类
- private Scroller mScroller;
- //刷新的View
- private RecyclerView mRefreshView;
- private Context mContext;
- private int mMaxScrollHeight;
- private boolean isFirst = true;
- public static final int NORMAL = 0;
- public static final int PULL_TO_REFRESH = 1;
- public static final int RELEASE_TO_REFRESH = 2;
- public static final int REFRESING = 3;
- private int mCurrentState;
- private int mTouchSlop;
- private OnRefreshListener listener;
- private boolean isPullDownMotion;
- private int lastVisible;
- public PullToRefreshRecycleView(Context context) {
- super(context);
- init(context);
- }
- public PullToRefreshRecycleView(Context context, AttributeSet attrs) {
- super(context, attrs);
- init(context);
- }
- private void init(Context context) {
- mContext = context;
- this.setOrientation(VERTICAL);
- mRefreshView = getRefreshView();
- mRefreshView.setBackgroundColor(Color.WHITE);
- LayoutParams listParams = new LayoutParams(-1, -1);
- mRefreshView.setLayoutParams(listParams);
- addView(mRefreshView);
- //加入HeaderView
- mHeaderView = new CustomHeaderView(context);
- LayoutParams params = new LayoutParams(-1, -2);
- mHeaderView.setLayoutParams(params);
- addView(mHeaderView, 0);
- //加入FooterView
- mFooterView = new CustomFooterView(context);
- LayoutParams fParams = new LayoutParams(-1, 200);
- mFooterView.setLayoutParams(fParams);
- addView(mFooterView, -1);
- //弹性滑动实现
- mScroller = new Scroller(context);
- mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
- }
- @Override
- protected void onSizeChanged(int w, int h, int oldw, int oldh) {
- super.onSizeChanged(w, h, oldw, oldh);
- //第一次获取相关參数,并隐藏HeaderView,FooterView
- if (isFirst) {
- mHeaderHeight = mHeaderView.getMeasuredHeight();
- mMaxScrollHeight = mHeaderHeight * 3;
- resetHeaderLayout(-mHeaderHeight);
- mFooterHeight = mFooterView.getMeasuredHeight();
- resetFooterLayout(-mFooterHeight);
- Log.v("@mHeaderHeight", mHeaderHeight + "");
- Log.v("@mFooterHeight", mFooterHeight + "");
- isFirst = false;
- }
- }
- private void resetHeaderLayout(int offset) {
- LayoutParams params = (LayoutParams) mHeaderView.getLayoutParams();
- params.topMargin = offset;
- mHeaderView.requestLayout();
- }
- private void resetFooterLayout(int offset) {
- LayoutParams params = (LayoutParams) mFooterView.getLayoutParams();
- params.bottomMargin = offset;
- mFooterView.requestLayout();
- }
- //按下时的位置,当事件被阻止时,第一次ActionDown事件,onTouchEvent无法获取这个位置
- //须要在onInterceptTouchEvent获取
- private float downY;
- @Override
- public boolean onInterceptTouchEvent(MotionEvent ev) {
- //假设当前是正在刷新而且是下拉状态,则当前视图处理事件
- if (isRefreshing && mScrollY < 0) {
- return true;
- }
- //假设当前是刷新状态,而且处于上拉状态,则视图不可进入下拉状态
- if (mScrollY >= 0 && isRefreshing)
- return false;
- boolean isIntercept = false;
- int action = ev.getAction();
- switch (action) {
- case MotionEvent.ACTION_DOWN:
- downY = ev.getY();
- break;
- case MotionEvent.ACTION_MOVE:
- //假设达到了滑动条件
- if (Math.abs(ev.getY() - downY) >= mTouchSlop) {
- if (ev.getY() - downY > 0) {//下拉
- isIntercept = isEnablePullDown();
- if (isIntercept)//设置下拉还是上滑的状态,true表示下拉动作
- isPullDownMotion = true;
- } else {//上滑
- isIntercept = isEnableLoadMore();
- if (isIntercept)//false表示上滑状态
- isPullDownMotion = false;
- }
- } else {
- isIntercept = false;
- }
- break;
- case MotionEvent.ACTION_CANCEL:
- //假设返回true,子视图假设包括点击事件。则无法进行处理
- isIntercept = false;
- break;
- case MotionEvent.ACTION_UP:
- isIntercept = false;
- break;
- }
- return isIntercept;
- }
- //记录当前滑动的位置
- private int mScrollY;
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- int action = event.getAction();
- switch (action) {
- case MotionEvent.ACTION_DOWN:
- //第一次推断时,downY仅仅能从intercept中获取,之后从这里获取
- downY = event.getY();
- break;
- case MotionEvent.ACTION_MOVE:
- float dY = event.getY() - downY;
- if (isPullDownMotion)//下拉
- doPullDownMoveEvent(dY);
- else {//自己主动载入很多其它
- doLoadMoreEvent(dY);
- }
- break;
- case MotionEvent.ACTION_UP:
- if (isPullDownMotion) {
- //处理下拉结果
- doPullDownResult();
- } else {
- //处理滑动载入很多其它结果
- doLoadMoreResult();
- }
- break;
- case MotionEvent.ACTION_CANCEL:
- //同ACTION_UP
- if (isPullDownMotion) {
- doPullDownResult();
- } else {
- doLoadMoreResult();
- }
- break;
- }
- return true;
- }
- /**
- * 处理载入很多其它
- */
- private void doLoadMoreResult() {
- //手指松开时,假设FooterView,没有全然滑动出来。自己主动滑动出来
- scrollTo(0, mFooterHeight);
- mScrollY = getScrollY();
- if (!isRefreshing) {
- isRefreshing = true;
- if (listener != null)
- listener.onLoadMore();
- }
- }
- /**
- * 载入很多其它完毕后调用
- */
- public void completeLoadMore() {
- scrollTo(0, 0);
- mScrollY = 0;
- isRefreshing = false;
- LinearLayoutManager manager = (LinearLayoutManager) mRefreshView.getLayoutManager();
- int count = manager.getItemCount();
- if (count > lastVisible + 1)//载入了很多其它数据
- mRefreshView.scrollToPosition(lastVisible + 1);
- }
- //处理载入很多其它
- private void doLoadMoreEvent(float y) {
- int scrollY = (int) (mScrollY - y);
- if (scrollY < 0) {
- scrollY = 0;
- }
- if (scrollY > mFooterHeight) {
- scrollY = mFooterHeight;
- }
- Log.v("@scrollY", scrollY + "");
- scrollTo(0, scrollY);
- }
- /**
- * 处理释放后的操作
- */
- private void doPullDownResult() {
- //先获取如今滑动到的位置
- mScrollY = getScrollY();
- switch (mCurrentState) {
- case PULL_TO_REFRESH:
- mCurrentState = NORMAL;
- mHeaderView.onNormal();
- smoothScrollTo(0);
- break;
- case RELEASE_TO_REFRESH:
- //松开时,假设是释放刷新。则開始进行刷新动作
- if (!isRefreshing) {
- //滑动到指定位置
- smoothScrollTo(-mHeaderHeight);
- mHeaderView.onRefreshing();
- isRefreshing = true;
- if (listener != null) {
- //运行刷新回调
- listener.onPullDownRefresh();
- }
- //假设当前滑动位置太靠下,则滑动到指定刷新位置
- } else if (mScrollY < -mHeaderHeight) {
- smoothScrollTo(-mHeaderHeight);
- }
- break;
- }
- }
- /**
- * 获取到数据后,调用
- */
- public void completeRefresh() {
- isRefreshing = false;
- mCurrentState = NORMAL;
- smoothScrollTo(0);
- }
- private void doPullDownMoveEvent(float y) {
- int scrollY = (int) (mScrollY - y * RATIO);
- if (scrollY > 0) {
- scrollY = 0;
- }
- if (scrollY < -mMaxScrollHeight) {
- scrollY = -mMaxScrollHeight;
- }
- scrollTo(0, scrollY);
- if (isRefreshing)
- return;
- //设置对应的状态
- if (scrollY == 0) {
- mCurrentState = NORMAL;
- mHeaderView.onNormal();
- } else if (scrollY <= 0 && scrollY > -mHeaderHeight) {
- mCurrentState = PULL_TO_REFRESH;
- mHeaderView.onPullToRefresh(Math.abs(scrollY));
- } else if (scrollY <= -mHeaderHeight && scrollY >= -mMaxScrollHeight) {
- mCurrentState = RELEASE_TO_REFRESH;
- mHeaderView.onReleaseToRefresh(Math.abs(scrollY));
- }
- }
- /**
- * 从当前位置滑动到指定位置
- * @param y 滑动到的位置
- */
- private void smoothScrollTo(int y) {
- int dY = y - mScrollY;
- mScroller.startScroll(0, mScrollY, 0, dY, 500);
- invalidate();
- }
- private RecyclerView getRefreshView() {
- mRefreshView = new RecyclerView(mContext);
- mRefreshView.setLayoutManager(new LinearLayoutManager(mContext, LinearLayoutManager.VERTICAL, false));
- mRefreshView.addItemDecoration(new CustomItemDecoration(mContext, CustomItemDecoration.VERTICAL_LIST));
- return mRefreshView;
- }
- public void setAdapter(RecyclerView.Adapter adapter) {
- mRefreshView.setAdapter(adapter);
- }
- /**
- * 推断列表是否在最顶端
- * @return
- */
- private boolean isEnablePullDown() {
- LinearLayoutManager manager = (LinearLayoutManager) mRefreshView.getLayoutManager();
- int firstVisible = manager.findFirstVisibleItemPosition();
- //当前还没有数据,能够进行下拉
- if(manager.getItemCount()==0)
- return true;
- return firstVisible == 0 && manager.getChildAt(0).getTop() == 0;
- }
- /**
- * 推断列表是否滑动到了最底部
- * @return
- */
- private boolean isEnableLoadMore() {
- LinearLayoutManager manager = (LinearLayoutManager) mRefreshView.getLayoutManager();
- lastVisible = manager.findLastVisibleItemPosition();
- int totalCount = manager.getItemCount();
- //假设没有数据,仅仅能下拉刷新
- if (totalCount == 0)
- return false;
- int bottom = manager.findViewByPosition(lastVisible).getBottom();
- int decorHeight = manager.getBottomDecorationHeight(mRefreshView.getChildAt(0));
- //最后一个child的底部位置在当前视图的上面
- return totalCount == lastVisible + 1 && bottom + decorHeight <= getMeasuredHeight();
- }
- @Override
- public void computeScroll() {
- if (mScroller.computeScrollOffset()) {
- scrollTo(0, mScroller.getCurrY());
- mScrollY = mScroller.getCurrY();
- invalidate();
- }
- }
- /**
- * 设置Footer的内容
- */
- public void setFooterViewState(boolean hasMoreData){
- if(hasMoreData){
- mFooterView.onRefreshing();
- }else{
- mFooterView.onNoData();
- }
- }
- public interface OnRefreshListener {
- void onPullDownRefresh();
- void onLoadMore();
- }
- public void setOnRefreshListener(OnRefreshListener listener) {
- this.listener = listener;
- }
- }
- private void init(Context context) {
- mContext = context;
- this.setOrientation(VERTICAL);
- mRefreshView = getRefreshView();
- mRefreshView.setBackgroundColor(Color.WHITE);
- LayoutParams listParams = new LayoutParams(-1, -1);
- mRefreshView.setLayoutParams(listParams);
- addView(mRefreshView);
- //加入HeaderView
- mHeaderView = new CustomHeaderView(context);
- LayoutParams params = new LayoutParams(-1, -2);
- mHeaderView.setLayoutParams(params);
- addView(mHeaderView, 0);
- //加入FooterView
- mFooterView = new CustomFooterView(context);
- LayoutParams fParams = new LayoutParams(-1, 200);
- mFooterView.setLayoutParams(fParams);
- addView(mFooterView, -1);
- //弹性滑动实现
- mScroller = new Scroller(context);
- mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
- }
- @Override
- protected void onSizeChanged(int w, int h, int oldw, int oldh) {
- super.onSizeChanged(w, h, oldw, oldh);
- //第一次获取相关參数,并隐藏HeaderView。FooterView
- if (isFirst) {
- mHeaderHeight = mHeaderView.getMeasuredHeight();
- mMaxScrollHeight = mHeaderHeight * 3;
- resetHeaderLayout(-mHeaderHeight);
- mFooterHeight = mFooterView.getMeasuredHeight();
- resetFooterLayout(-mFooterHeight);
- Log.v("@mHeaderHeight", mHeaderHeight + "");
- Log.v("@mFooterHeight", mFooterHeight + "");
- isFirst = false;
- }
- }
在这种方法里面,我们获取了HeaderView,FooterView的測量高。而且,我们设置了HeaderView。FooterView的margin值,隐藏了头部和尾部。
- //按下时的位置,当事件被阻止时。第一次ActionDown事件,onTouchEvent无法获取这个位置
- //须要在onInterceptTouchEvent获取
- private float downY;
- @Override
- public boolean onInterceptTouchEvent(MotionEvent ev) {
- //假设当前是正在刷新而且是下拉状态,则当前视图处理事件
- if (isRefreshing && mScrollY < 0) {
- return true;
- }
- //假设当前是刷新状态。而且处于上拉状态。则视图不可进入下拉状态
- if (mScrollY >= 0 && isRefreshing)
- return false;
- boolean isIntercept = false;
- int action = ev.getAction();
- switch (action) {
- case MotionEvent.ACTION_DOWN:
- downY = ev.getY();
- break;
- case MotionEvent.ACTION_MOVE:
- //假设达到了滑动条件
- if (Math.abs(ev.getY() - downY) >= mTouchSlop) {
- if (ev.getY() - downY > 0) {//下拉
- isIntercept = isEnablePullDown();
- if (isIntercept)//设置下拉还是上滑的状态,true表示下拉动作
- isPullDownMotion = true;
- } else {//上滑
- isIntercept = isEnableLoadMore();
- if (isIntercept)//false表示上滑状态
- isPullDownMotion = false;
- }
- } else {
- isIntercept = false;
- }
- break;
- case MotionEvent.ACTION_CANCEL:
- //假设返回true,子视图假设包括点击事件,则无法进行处理
- isIntercept = false;
- break;
- case MotionEvent.ACTION_UP:
- isIntercept = false;
- break;
- }
- return isIntercept;
- }
- //假设当前是正在刷新而且是下拉状态,则当前视图处理事件
- if (isRefreshing && mScrollY < 0) {
- return true;
- }
- //假设当前是刷新状态,而且处于上拉状态。则视图不可进入下拉状态
- if (mScrollY >= 0 && isRefreshing)
- return false;
假设当前为下拉而且在刷新状态,则返回true,表示拦截事件,RecyclerView不可滑动。假设当前是滑动载入很多其它。而且刷新状态。则不拦截,由于后面我想在滑动载入很多其它时,RecyclerView能够滑动。 截止后面。在ACTION_DOWN事件中,我们记录下按下的y轴位置。然后是ACTION_MOVE;
- //假设达到了滑动条件
- if (Math.abs(ev.getY() - downY) >= mTouchSlop) {
- if (ev.getY() - downY > 0) {//下拉
- isIntercept = isEnablePullDown();
- if (isIntercept)//设置下拉还是上滑的状态,true表示下拉动作
- isPullDownMotion = true;
- } else {//上滑
- isIntercept = isEnableLoadMore();
- if (isIntercept)//false表示上滑状态
- isPullDownMotion = false;
- }
- } else {
- isIntercept = false;
- }
假设当前滑动,大于这个值,继续走里面的if推断,假设当前是下拉状态,而且是能够下拉。那么拦截事件,否则进行滑动载入很多其它。假设满足滑动载入很多其它的条件,那么能够向上滑动。而且整个过程,用isPullDownMotion记录下了是向上还是向下的动作。后面在onTouchEvent中须要使用。最后,ACTION_UP和ACTION_CANCEL不拦截。假设拦截,会影响到子View的点击事件。
- //记录当前滑动的位置
- private int mScrollY;
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- int action = event.getAction();
- switch (action) {
- case MotionEvent.ACTION_DOWN:
- //第一次推断时,downY仅仅能从intercept中获取。之后从这里获取
- downY = event.getY();
- break;
- case MotionEvent.ACTION_MOVE:
- float dY = event.getY() - downY;
- if (isPullDownMotion)//下拉
- doPullDownMoveEvent(dY);
- else {//自己主动载入很多其它
- doLoadMoreEvent(dY);
- }
- break;
- case MotionEvent.ACTION_UP:
- if (isPullDownMotion) {
- //处理下拉结果
- doPullDownResult();
- } else {
- //处理滑动载入很多其它结果
- doLoadMoreResult();
- }
- break;
- case MotionEvent.ACTION_CANCEL:
- //同ACTION_UP
- if (isPullDownMotion) {
- doPullDownResult();
- } else {
- doLoadMoreResult();
- }
- break;
- }
- return true;
- }
- private void doPullDownMoveEvent(float y) {
- int scrollY = (int) (mScrollY - y * RATIO);
- if (scrollY > 0) {
- scrollY = 0;
- }
- if (scrollY < -mMaxScrollHeight) {
- scrollY = -mMaxScrollHeight;
- }
- scrollTo(0, scrollY);
- if (isRefreshing)
- return;
- //设置对应的状态
- if (scrollY == 0) {
- mCurrentState = NORMAL;
- mHeaderView.onNormal();
- } else if (scrollY <= 0 && scrollY > -mHeaderHeight) {
- mCurrentState = PULL_TO_REFRESH;
- mHeaderView.onPullToRefresh(Math.abs(scrollY));
- } else if (scrollY <= -mHeaderHeight && scrollY >= -mMaxScrollHeight) {
- mCurrentState = RELEASE_TO_REFRESH;
- mHeaderView.onReleaseToRefresh(Math.abs(scrollY));
- }
- }
这样就完毕了触摸滑动。 后面。我们在通过滑动的位置,设置对应的状态。并回调HeaderView的各个状态的方法。
- /**
- * 处理释放后的操作
- */
- private void doPullDownResult() {
- //先获取如今滑动到的位置
- mScrollY = getScrollY();
- switch (mCurrentState) {
- case PULL_TO_REFRESH:
- mCurrentState = NORMAL;
- mHeaderView.onNormal();
- smoothScrollTo(0);
- break;
- case RELEASE_TO_REFRESH:
- //松开时。假设是释放刷新,则開始进行刷新动作
- if (!isRefreshing) {
- //滑动到指定位置
- smoothScrollTo(-mHeaderHeight);
- mHeaderView.onRefreshing();
- isRefreshing = true;
- if (listener != null) {
- //运行刷新回调
- listener.onPullDownRefresh();
- }
- //假设当前滑动位置太靠下,则滑动到指定刷新位置
- } else if (mScrollY < -mHeaderHeight) {
- smoothScrollTo(-mHeaderHeight);
- }
- break;
- }
- }
- /**
- * 从当前位置滑动到指定位置
- * @param y 滑动到的位置
- */
- private void smoothScrollTo(int y) {
- int dY = y - mScrollY;
- mScroller.startScroll(0, mScrollY, 0, dY, 500);
- invalidate();
- }
这种方法,必须要配合computeScroll使用。不然是没有效果的。详细的原因,须要查看View的绘制流程,这里我就不详细分析。
- @Override
- public void computeScroll() {
- if (mScroller.computeScrollOffset()) {
- scrollTo(0, mScroller.getCurrY());
- mScrollY = mScroller.getCurrY();
- invalidate();
- }
- }
这样,每次都移动一小段位置,就实现了平滑滑动的效果。
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- tools:context=".MainActivity">
- <com.mjc.recyclerviewdemo.refresh.PullToRefreshRecycleView
- android:id="@+id/prrv"
- android:layout_width="match_parent"
- android:layout_height="match_parent"/>
- </LinearLayout>
- mPRRV = (PullToRefreshRecycleView) findViewById(R.id.prrv);
- mPRRV.setOnRefreshListener(new PullToRefreshRecycleView.OnRefreshListener() {
- @Override
- public void onPullDownRefresh() {
- mHandler.postDelayed(new Runnable() {
- @Override
- public void run() {
- datas.add(0, "add");
- mAdapter.notifyDataSetChanged();
- mPRRV.completeRefresh();
- }
- }, 2000);
- }
- @Override
- public void onLoadMore() {
- mHandler.postDelayed(new Runnable() {
- @Override
- public void run() {
- datas.add("李四");
- datas.add("王五");
- datas.add("张三");
- datas.add("李四");
- datas.add("王五");
- datas.add("张三");
- mAdapter.notifyDataSetChanged();
- mPRRV.completeLoadMore();
- }
- }, 1000);
- }
- });
RecyclerView下拉刷新和载入很多其它的更多相关文章
- RecyclerView下拉刷新上拉加载(一)
listview下拉刷新上拉加载扩展(一) http://blog.csdn.net/baiyuliang2013/article/details/50252561 listview下拉刷新上拉加载扩 ...
- 带你实现开发者头条APP(五)--RecyclerView下拉刷新上拉加载
title: 带你实现开发者头条APP(五)--RecyclerView下拉刷新上拉加载 tags: -RecyclerView,下拉刷新,上拉加载更多 grammar_cjkRuby: true - ...
- RecyclerView下拉刷新上拉加载(三)—对Adapter的封装
RecyclerView下拉刷新上拉加载(一) http://blog.csdn.net/baiyuliang2013/article/details/51506036 RecyclerView下拉刷 ...
- RecyclerView下拉刷新上拉加载更多
现在Android里都建议用RecyclerView代替ListView和GridView,所以下拉刷新和上拉加载更多也需要实现.下拉刷新可以用SwipeRefreshLayout 包裹Recycle ...
- 实现RecyclerView下拉刷新和上拉加载更多以及RecyclerView线性、网格、瀑布流效果演示
实现RecyclerView下拉刷新和上拉加载更多以及RecyclerView线性.网格.瀑布流效果演示 效果预览 实例APP 小米应用商店 使用方法 build.gradle文件 dependenc ...
- RecyclerView下拉刷新和上拉加载更多实现
RecyclerView下拉刷新和上拉加载更多实现 转 https://www.jianshu.com/p/4ea7c2d95ecf 在Android开发中,RecyclerView算是使用频率非 ...
- 封装RecyclerViewAdapter实现RecyclerView下拉刷新上拉载入很多其它
实现 关于下拉刷新使用的是github上的项目Ultra Pull To Refresh项目. gradle依赖例如以下: compile 'in.srain.cube:ultra-ptr:1.0.1 ...
- RecyclerView 下拉刷新上拉加载
步骤: 首先直接定义一个XRecyclerView继承RecyclerView,重写他的三个构造方法. init(Context mContext)方法用来初始化底部加载的view 回到XRecycl ...
- RecyclerView下拉刷新上拉加载(二)
listview下拉刷新上拉加载扩展(一) http://blog.csdn.net/baiyuliang2013/article/details/50252561 listview下拉刷新上拉加载扩 ...
随机推荐
- 常见bug分析
变量类型不匹配,形参和实参类型不匹配,隐式类型转换,变量类型赋值不匹配, 工具不熟悉,导致逻辑错误,查看代码,测试驱动开发,完整的测试用例,覆盖所有分支, 变量超出范围,对于大的数据要特别注意, 工具 ...
- vi-vim和linux常用快捷键
移动光标 上 k 下 j 左 h 右 l 移动光标到当前行行尾首 ^ 移动光标到当前行行尾 $ 移动到文件的第一行 gg 移动到文件的最后一行 G 移动到第1 ...
- dd---复制文件并对原文件的内容进行转换和格式化处理
dd命令用于复制文件并对原文件的内容进行转换和格式化处理.dd命令功能很强大的,对于一些比较底层的问题,使用dd命令往往可以得到出人意料的效果.用的比较多的还是用dd来备份裸设备.但是不推荐,如果需要 ...
- Laravel API 允许跨域访问
服务器A请求服务器B的接口,那么一般会出现跨域问题.全解跨域请求处理办法 XMLHttpRequest cannot load http://api.console.vms3.com/api/user ...
- 阿里云上如何找到虚拟主机和用户名登录FileZilla软件?
0.少玩游戏 1.登录阿里云官网 :https://www.aliyun.com/ 2.点击自己的旁边的名称进入进入自己的页面 3.购买的域名和主机会在这里显示,点击域名与网站(万网)>云虚拟主 ...
- LocalDateTime与mysql日期类型的交互(基于mybatis)
众所周知,在实体Entity里面,可以使用Java.sql.Date.java.sql.Timestamp.java.util.Date来映射到数据库的date.timestamp.datetime等 ...
- Android Studio获取开发版SHA1值和发布版SHA1值,详细过程
转自原文 Android Studio获取开发版SHA1值和发布版SHA1值的史上最详细方法 前言: 今天我想把百度地图的定位集成到项目中来,想写个小小的案例,实现一下,但在集成百度地图时首先要申请秘 ...
- 从C10K到C10M高性能网络的探索与实践
在高性能网络的场景下,C10K是一个具有里程碑意义的场景,15年前它给互联网领域带来了非常大的挑战.发展至今,我们已经进入C10M的场景进行网络性能优化. 这期间有怎样的发展和趋势?环绕着各类指标分别 ...
- 9.java 操作mongodb插入、读取、修改以及删除基础
1 package mongodb; import java.net.UnknownHostException; import java.util.ArrayList; import java.uti ...
- 【基础篇】DatePickerDialog日期控件的基本使用(二) ——分别获取年、月、日、时、分
项目步骤: 1.在Main.xml布局文件中定义对应的组件,Main.xml内容如下: <?xml version="1.0" encoding="utf-8&qu ...