文档章节

上拉刷新下拉加载PullToRefreshLayout

lsy999
 lsy999
发布于 2017/04/12 10:17
字数 2776
阅读 22
收藏 0

java    

pullable代码

package com.example.lsy.tianmi.base.commonview;

public interface Pullable
{
   /**
    * 判断是否可以下拉,如果不需要下拉功能可以直接return false
    * 
    * @return true如果可以下拉否则返回false
    */
   boolean canPullDown();

   /**
    * 判断是否可以上拉,如果不需要上拉功能可以直接return false
    * 
    * @return true如果可以上拉否则返回false
    */
   boolean canPullUp();
}
PullableScrollview   注意这个可以改成你想要的 只要继承它,比如继承scrollView
package com.example.lsy.tianmi.base.commonview;

import android.content.Context;
import android.util.AttributeSet;

import android.widget.ScrollView;

public class PullableScrollview extends ScrollView implements Pullable
{

   public PullableScrollview(Context context)
   {
      super(context);
   }

   public PullableScrollview(Context context, AttributeSet attrs)
   {
      super(context, attrs);
   }

   public PullableScrollview(Context context, AttributeSet attrs, int defStyle)
   {
      super(context, attrs, defStyle);
   }

   @Override
   public boolean canPullDown()
   {
      if (getScrollY() == 0)
         return true;
      else
         return false;
   }

   @Override
   public boolean canPullUp()
   {
      if (getScrollY() >= (getChildAt(0).getHeight() - getMeasuredHeight()))
         return true;
      else
         return false;
   }
}
PullToRefreshLayout
package com.example.lsy.tianmi.base.commonview;

import android.content.Context;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AnimationUtils;
import android.view.animation.LinearInterpolator;
import android.view.animation.RotateAnimation;
import android.widget.RelativeLayout;
import android.widget.TextView;


import com.example.lsy.tianmi.R;

import java.util.Timer;
import java.util.TimerTask;

/**
 * 自定义的布局,用来管理三个子控件,其中一个是下拉头,一个是包含内容的pullableView(可以是实现Pullable接口的的任何View),
 * 还有一个上拉头,更多详解见博客http://blog.csdn.net/zhongkejingwang/article/details/38868463
 * 
 * @author 陈靖
 */
public class PullToRefreshLayout extends RelativeLayout
{
   public static final String TAG = "PullToRefreshLayout";
   // 初始状态
   public static final int INIT = 0;
   // 释放刷新
   public static final int RELEASE_TO_REFRESH = 1;
   // 正在刷新
   public static final int REFRESHING = 2;
   // 释放加载
   public static final int RELEASE_TO_LOAD = 3;
   // 正在加载
   public static final int LOADING = 4;
   // 操作完毕
   public static final int DONE = 5;
   // 当前状态
   private int state = INIT;
   // 刷新回调接口
   private OnRefreshListener mListener;
   // 刷新成功
   public static final int SUCCEED = 0;
   // 刷新失败
   public static final int FAIL = 1;
   // 按下Y坐标,上一个事件点Y坐标
   private float downY, lastY;

   // 下拉的距离。注意:pullDownY和pullUpY不可能同时不为0
   public float pullDownY = 0;
   // 上拉的距离
   private float pullUpY = 0;

   // 释放刷新的距离
   private float refreshDist = 200;
   // 释放加载的距离
   private float loadmoreDist = 200;

   private MyTimer timer;
   // 回滚速度
   public float MOVE_SPEED = 8;
   // 第一次执行布局
   private boolean isLayout = false;
   // 在刷新过程中滑动操作
   private boolean isTouch = false;
   // 手指滑动距离与下拉头的滑动距离比,中间会随正切函数变化
   private float radio = 2;

   // 下拉箭头的转180°动画
   private RotateAnimation rotateAnimation;
   // 均匀旋转动画
   private RotateAnimation refreshingAnimation;

   // 下拉头
   private View refreshView;
   // 下拉的箭头
   private View pullView;
   // 正在刷新的图标
   private View refreshingView;
   // 刷新结果图标
   private View refreshStateImageView;
   // 刷新结果:成功或失败
   private TextView refreshStateTextView;

   // 上拉头
   private View loadmoreView;
   // 上拉的箭头
   private View pullUpView;
   // 正在加载的图标
   private View loadingView;
   // 加载结果图标
   private View loadStateImageView;
   // 加载结果:成功或失败
   private TextView loadStateTextView;

   // 实现了Pullable接口的View
   private View pullableView;
   // 过滤多点触碰
   private int mEvents;
   // 这两个变量用来控制pull的方向,如果不加控制,当情况满足可上拉又可下拉时没法下拉
   private boolean canPullDown = true;
   private boolean canPullUp = true;

   private Context mContext;

   /**
    * 执行自动回滚的handler
    */
   Handler updateHandler = new Handler()
   {

      @Override
      public void handleMessage(Message msg)
      {
         // 回弹速度随下拉距离moveDeltaY增大而增大
         MOVE_SPEED = (float) (8 + 5 * Math.tan(Math.PI / 2
               / getMeasuredHeight() * (pullDownY + Math.abs(pullUpY))));
         if (!isTouch)
         {
            // 正在刷新,且没有往上推的话则悬停,显示"正在刷新..."
            if (state == REFRESHING && pullDownY <= refreshDist)
            {
               pullDownY = refreshDist;
               timer.cancel();
            } else if (state == LOADING && -pullUpY <= loadmoreDist)
            {
               pullUpY = -loadmoreDist;
               timer.cancel();
            }

         }
         if (pullDownY > 0)
            pullDownY -= MOVE_SPEED;
         else if (pullUpY < 0)
            pullUpY += MOVE_SPEED;
         if (pullDownY < 0)
         {
            // 已完成回弹
            pullDownY = 0;
            pullView.clearAnimation();
            // 隐藏下拉头时有可能还在刷新,只有当前状态不是正在刷新时才改变状态
            if (state != REFRESHING && state != LOADING)
               changeState(INIT);
            timer.cancel();
            requestLayout();
         }
         if (pullUpY > 0)
         {
            // 已完成回弹
            pullUpY = 0;
            pullUpView.clearAnimation();
            // 隐藏上拉头时有可能还在刷新,只有当前状态不是正在刷新时才改变状态
            if (state != REFRESHING && state != LOADING)
               changeState(INIT);
            timer.cancel();
            requestLayout();
         }
         Log.d("handle", "handle");
         // 刷新布局,会自动调用onLayout
         requestLayout();
         // 没有拖拉或者回弹完成
         if (pullDownY + Math.abs(pullUpY) == 0)
            timer.cancel();
      }

   };

   public void setOnRefreshListener(OnRefreshListener listener)
   {
      mListener = listener;
   }

   public PullToRefreshLayout(Context context)
   {
      super(context);
      initView(context);
   }

   public PullToRefreshLayout(Context context, AttributeSet attrs)
   {
      super(context, attrs);
      initView(context);
   }

   public PullToRefreshLayout(Context context, AttributeSet attrs, int defStyle)
   {
      super(context, attrs, defStyle);
      initView(context);
   }

   private void initView(Context context)
   {
      mContext = context;
      timer = new MyTimer(updateHandler);
      rotateAnimation = (RotateAnimation) AnimationUtils.loadAnimation(
            context, R.anim.reverse_anim);
      refreshingAnimation = (RotateAnimation) AnimationUtils.loadAnimation(
            context, R.anim.rotating);
      // 添加匀速转动动画
      LinearInterpolator lir = new LinearInterpolator();
      rotateAnimation.setInterpolator(lir);
      refreshingAnimation.setInterpolator(lir);
   }

   private void hide()
   {
      timer.schedule(5);
   }

   /**
    * 完成刷新操作,显示刷新结果。注意:刷新完成后一定要调用这个方法
    */
   /**
    * @param refreshResult
    *            PullToRefreshLayout.SUCCEED代表成功,PullToRefreshLayout.FAIL代表失败
    */
   public void refreshFinish(int refreshResult)
   {
      refreshingView.clearAnimation();
      refreshingView.setVisibility(View.GONE);
      switch (refreshResult)
      {
      case SUCCEED:
         // 刷新成功
         refreshStateImageView.setVisibility(View.VISIBLE);
         refreshStateTextView.setText(R.string.refresh_succeed);
         refreshStateImageView
               .setBackgroundResource(R.mipmap.refresh_succeed);
         break;
      case FAIL:
      default:
         // 刷新失败
         refreshStateImageView.setVisibility(View.VISIBLE);
         refreshStateTextView.setText(R.string.refresh_fail);
         refreshStateImageView
               .setBackgroundResource(R.mipmap.refresh_failed);
         break;
      }
      if (pullDownY > 0)
      {
         // 刷新结果停留1秒
         new Handler()
         {
            @Override
            public void handleMessage(Message msg)
            {
               changeState(DONE);
               hide();
            }
         }.sendEmptyMessageDelayed(0, 1000);
      } else
      {
         changeState(DONE);
         hide();
      }
   }

   /**
    * 加载完毕,显示加载结果。注意:加载完成后一定要调用这个方法
    * 
    * @param refreshResult
    *            PullToRefreshLayout.SUCCEED代表成功,PullToRefreshLayout.FAIL代表失败
    */
   public void loadmoreFinish(int refreshResult)
   {
      loadingView.clearAnimation();
      loadingView.setVisibility(View.GONE);
      switch (refreshResult)
      {
      case SUCCEED:
         // 加载成功
         loadStateImageView.setVisibility(View.VISIBLE);
         loadStateTextView.setText(R.string.load_succeed);
         loadStateImageView.setBackgroundResource(R.mipmap.load_succeed);
         break;
      case FAIL:
      default:
         // 加载失败
         loadStateImageView.setVisibility(View.VISIBLE);
         loadStateTextView.setText(R.string.load_fail);
         loadStateImageView.setBackgroundResource(R.mipmap.load_failed);
         break;
      }
      if (pullUpY < 0)
      {
         // 刷新结果停留1秒
         new Handler()
         {
            @Override
            public void handleMessage(Message msg)
            {
               changeState(DONE);
               hide();
            }
         }.sendEmptyMessageDelayed(0, 1000);
      } else
      {
         changeState(DONE);
         hide();
      }
   }

   private void changeState(int to)
   {
      state = to;
      switch (state)
      {
      case INIT:
         // 下拉布局初始状态
         refreshStateImageView.setVisibility(View.GONE);
         refreshStateTextView.setText(R.string.pull_to_refresh);
         pullView.clearAnimation();
         pullView.setVisibility(View.VISIBLE);
         // 上拉布局初始状态
         loadStateImageView.setVisibility(View.GONE);
         loadStateTextView.setText(R.string.pullup_to_load);
         pullUpView.clearAnimation();
         pullUpView.setVisibility(View.VISIBLE);
         break;
      case RELEASE_TO_REFRESH:
         // 释放刷新状态
         refreshStateTextView.setText(R.string.release_to_refresh);
         pullView.startAnimation(rotateAnimation);
         break;
      case REFRESHING:
         // 正在刷新状态
         pullView.clearAnimation();
         refreshingView.setVisibility(View.VISIBLE);
         pullView.setVisibility(View.INVISIBLE);
         refreshingView.startAnimation(refreshingAnimation);
         refreshStateTextView.setText(R.string.refreshing);
         break;
      case RELEASE_TO_LOAD:
         // 释放加载状态
         loadStateTextView.setText(R.string.release_to_load);
         pullUpView.startAnimation(rotateAnimation);
         break;
      case LOADING:
         // 正在加载状态
         pullUpView.clearAnimation();
         loadingView.setVisibility(View.VISIBLE);
         pullUpView.setVisibility(View.INVISIBLE);
         loadingView.startAnimation(refreshingAnimation);
         loadStateTextView.setText(R.string.loading);
         break;
      case DONE:
         // 刷新或加载完毕,啥都不做
         break;
      }
   }

   /**
    * 不限制上拉或下拉
    */
   private void releasePull()
   {
      canPullDown = true;
      canPullUp = true;
   }

   /*
    * (非 Javadoc)由父控件决定是否分发事件,防止事件冲突
    * 
    * @see android.view.ViewGroup#dispatchTouchEvent(android.view.MotionEvent)
    */
   @Override
   public boolean dispatchTouchEvent(MotionEvent ev)
   {
      switch (ev.getActionMasked())
      {
      case MotionEvent.ACTION_DOWN:
         downY = ev.getY();
         lastY = downY;
         timer.cancel();
         mEvents = 0;
         releasePull();
         break;
      case MotionEvent.ACTION_POINTER_DOWN:
      case MotionEvent.ACTION_POINTER_UP:
         // 过滤多点触碰
         mEvents = -1;
         break;
      case MotionEvent.ACTION_MOVE:
         if (mEvents == 0)
         {
            if (pullDownY > 0
                  || (((Pullable) pullableView).canPullDown()
                        && canPullDown && state != LOADING))
            {
               // 可以下拉,正在加载时不能下拉
               // 对实际滑动距离做缩小,造成用力拉的感觉
               pullDownY = pullDownY + (ev.getY() - lastY) / radio;
               if (pullDownY < 0)
               {
                  pullDownY = 0;
                  canPullDown = false;
                  canPullUp = true;
               }
               if (pullDownY > getMeasuredHeight())
                  pullDownY = getMeasuredHeight();
               if (state == REFRESHING)
               {
                  // 正在刷新的时候触摸移动
                  isTouch = true;
               }
            } else if (pullUpY < 0
                  || (((Pullable) pullableView).canPullUp() && canPullUp && state != REFRESHING))
            {
               // 可以上拉,正在刷新时不能上拉
               pullUpY = pullUpY + (ev.getY() - lastY) / radio;
               if (pullUpY > 0)
               {
                  pullUpY = 0;
                  canPullDown = true;
                  canPullUp = false;
               }
               if (pullUpY < -getMeasuredHeight())
                  pullUpY = -getMeasuredHeight();
               if (state == LOADING)
               {
                  // 正在加载的时候触摸移动
                  isTouch = true;
               }
            } else
               releasePull();
         } else
            mEvents = 0;
         lastY = ev.getY();
         // 根据下拉距离改变比例
         radio = (float) (2 + 2 * Math.tan(Math.PI / 2 / getMeasuredHeight()
               * (pullDownY + Math.abs(pullUpY))));
         if (pullDownY > 0 || pullUpY < 0)
            requestLayout();
         if (pullDownY > 0)
         {
            if (pullDownY <= refreshDist
                  && (state == RELEASE_TO_REFRESH || state == DONE))
            {
               // 如果下拉距离没达到刷新的距离且当前状态是释放刷新,改变状态为下拉刷新
               changeState(INIT);
            }
            if (pullDownY >= refreshDist && state == INIT)
            {
               // 如果下拉距离达到刷新的距离且当前状态是初始状态刷新,改变状态为释放刷新
               changeState(RELEASE_TO_REFRESH);
            }
         } else if (pullUpY < 0)
         {
            // 下面是判断上拉加载的,同上,注意pullUpY是负值
            if (-pullUpY <= loadmoreDist
                  && (state == RELEASE_TO_LOAD || state == DONE))
            {
               changeState(INIT);
            }
            // 上拉操作
            if (-pullUpY >= loadmoreDist && state == INIT)
            {
               changeState(RELEASE_TO_LOAD);
            }

         }
         // 因为刷新和加载操作不能同时进行,所以pullDownY和pullUpY不会同时不为0,因此这里用(pullDownY +
         // Math.abs(pullUpY))就可以不对当前状态作区分了
         if ((pullDownY + Math.abs(pullUpY)) > 8)
         {
            // 防止下拉过程中误触发长按事件和点击事件
            ev.setAction(MotionEvent.ACTION_CANCEL);
         }
         break;
      case MotionEvent.ACTION_UP:
         if (pullDownY > refreshDist || -pullUpY > loadmoreDist)
         // 正在刷新时往下拉(正在加载时往上拉),释放后下拉头(上拉头)不隐藏
         {
            isTouch = false;
         }
         if (state == RELEASE_TO_REFRESH)
         {
            changeState(REFRESHING);
            // 刷新操作
            if (mListener != null)
               mListener.onRefresh(this);
         } else if (state == RELEASE_TO_LOAD)
         {
            changeState(LOADING);
            // 加载操作
            if (mListener != null)
               mListener.onLoadMore(this);
         }
         hide();
      default:
         break;
      }
      // 事件分发交给父类
      super.dispatchTouchEvent(ev);
      return true;
   }

   /**
    * @author chenjing 自动模拟手指滑动的task
    * 
    */
   private class AutoRefreshAndLoadTask extends
         AsyncTask<Integer, Float, String>
   {

      @Override
      protected String doInBackground(Integer... params)
      {
         while (pullDownY < 4 / 3 * refreshDist)
         {
            pullDownY += MOVE_SPEED;
            publishProgress(pullDownY);
            try
            {
               Thread.sleep(params[0]);
            } catch (InterruptedException e)
            {
               e.printStackTrace();
            }
         }
         return null;
      }

      @Override
      protected void onPostExecute(String result)
      {
         changeState(REFRESHING);
         // 刷新操作
         if (mListener != null)
            mListener.onRefresh(PullToRefreshLayout.this);
         hide();
      }

      @Override
      protected void onProgressUpdate(Float... values)
      {
         if (pullDownY > refreshDist)
            changeState(RELEASE_TO_REFRESH);
         requestLayout();
      }

   }

   /**
    * 自动刷新
    */
   public void autoRefresh()
   {
      AutoRefreshAndLoadTask task = new AutoRefreshAndLoadTask();
      task.execute(20);
   }

   /**
    * 自动加载
    */
   public void autoLoad()
   {
      pullUpY = -loadmoreDist;
      requestLayout();
      changeState(LOADING);
      // 加载操作
      if (mListener != null)
         mListener.onLoadMore(this);
   }

   private void initView()
   {
      // 初始化下拉布局
      pullView = refreshView.findViewById(R.id.pull_icon);
      refreshStateTextView = (TextView) refreshView
            .findViewById(R.id.state_tv);
      refreshingView = refreshView.findViewById(R.id.refreshing_icon);
      refreshStateImageView = refreshView.findViewById(R.id.state_iv);
      // 初始化上拉布局
      pullUpView = loadmoreView.findViewById(R.id.pullup_icon);
      loadStateTextView = (TextView) loadmoreView
            .findViewById(R.id.loadstate_tv);
      loadingView = loadmoreView.findViewById(R.id.loading_icon);
      loadStateImageView = loadmoreView.findViewById(R.id.loadstate_iv);
   }

   @Override
   protected void onLayout(boolean changed, int l, int t, int r, int b)
   {
      Log.d("Test", "Test");
      if (!isLayout)
      {
         // 这里是第一次进来的时候做一些初始化
         refreshView = getChildAt(0);
         pullableView = getChildAt(1);
         loadmoreView = getChildAt(2);
         isLayout = true;
         initView();
         refreshDist = ((ViewGroup) refreshView).getChildAt(0)
               .getMeasuredHeight();
         loadmoreDist = ((ViewGroup) loadmoreView).getChildAt(0)
               .getMeasuredHeight();
      }
      // 改变子控件的布局,这里直接用(pullDownY + pullUpY)作为偏移量,这样就可以不对当前状态作区分
      refreshView.layout(0,
            (int) (pullDownY + pullUpY) - refreshView.getMeasuredHeight(),
            refreshView.getMeasuredWidth(), (int) (pullDownY + pullUpY));
      pullableView.layout(0, (int) (pullDownY + pullUpY),
            pullableView.getMeasuredWidth(), (int) (pullDownY + pullUpY)
                  + pullableView.getMeasuredHeight());
      loadmoreView.layout(0,
            (int) (pullDownY + pullUpY) + pullableView.getMeasuredHeight(),
            loadmoreView.getMeasuredWidth(),
            (int) (pullDownY + pullUpY) + pullableView.getMeasuredHeight()
                  + loadmoreView.getMeasuredHeight());
   }

   class MyTimer
   {
      private Handler handler;
      private Timer timer;
      private MyTask mTask;

      public MyTimer(Handler handler)
      {
         this.handler = handler;
         timer = new Timer();
      }

      public void schedule(long period)
      {
         if (mTask != null)
         {
            mTask.cancel();
            mTask = null;
         }
         mTask = new MyTask(handler);
         timer.schedule(mTask, 0, period);
      }

      public void cancel()
      {
         if (mTask != null)
         {
            mTask.cancel();
            mTask = null;
         }
      }

      class MyTask extends TimerTask
      {
         private Handler handler;

         public MyTask(Handler handler)
         {
            this.handler = handler;
         }

         @Override
         public void run()
         {
            handler.obtainMessage().sendToTarget();
         }

      }
   }

   /**
    * 刷新加载回调接口
    * 
    * @author chenjing
    * 
    */
   public interface OnRefreshListener
   {
      /**
       * 刷新操作
       */
      void onRefresh(PullToRefreshLayout pullToRefreshLayout);

      /**
       * 加载操作
       */
      void onLoadMore(PullToRefreshLayout pullToRefreshLayout);
   }

}

anim

progressbar

<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
        android:drawable="@mipmap/loading"
        android:fromDegrees="0"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toDegrees="360">
</rotate>

reverse_anim

<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="100"
    android:fillAfter="true"
    android:fromDegrees="0"
    android:pivotX="50%"
    android:pivotY="50%"
    android:repeatCount="0"
    android:toDegrees="180" >

</rotate>

rotating

<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1500"
    android:fillAfter="true"
    android:fromDegrees="0"
    android:pivotX="50%"
    android:pivotY="50%"
    android:repeatCount="-1"
    android:toDegrees="360" >

</rotate>

strings

<string name="pull_to_refresh">下拉刷新</string>
<string name="release_to_refresh">释放立即刷新</string>
<string name="refreshing">正在刷新...</string>
<string name="refresh_succeed">刷新成功</string>
<string name="refresh_fail">已是最新</string>
<string name="pullup_to_load">上拉加载更多</string>
<string name="release_to_load">释放立即加载</string>
<string name="loading">正在加载...</string>
<string name="load_succeed">加载成功</string>
<string name="load_fail">已全部加载</string>

load_more

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/loadmore_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/bar_orange" >

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:paddingBottom="10dp"
        android:paddingTop="10dp" >

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true" >

            <ImageView
                android:id="@+id/pullup_icon"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerVertical="true"
                android:layout_marginLeft="60dp"
                android:background="@mipmap/pullup_icon_big" />

            <ImageView
                android:id="@+id/loading_icon"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerVertical="true"
                android:layout_marginLeft="60dp"
                android:src="@mipmap/loading"
                android:visibility="gone" />

            <TextView
                android:id="@+id/loadstate_tv"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerInParent="true"
                android:text="@string/pullup_to_load"
                android:textColor="@color/black"
                android:textSize="16sp" />

            <ImageView
                android:id="@+id/loadstate_iv"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerVertical="true"
                android:layout_marginRight="8dp"
                android:layout_toLeftOf="@id/loadstate_tv"
                android:visibility="gone" />
        </RelativeLayout>
    </RelativeLayout>

</RelativeLayout>

refresh_head

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/head_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/bar_orange" >

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:paddingBottom="10dp"
        android:paddingTop="10dp" >

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true" >

            <ImageView
                android:id="@+id/pull_icon"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerVertical="true"
                android:layout_marginLeft="60dp"
                android:background="@mipmap/pull_icon_big" />

            <ImageView
                android:id="@+id/refreshing_icon"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerVertical="true"
                android:layout_marginLeft="60dp"
                android:background="@mipmap/refreshing"
                android:visibility="gone" />

            <TextView
                android:id="@+id/state_tv"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerInParent="true"
                android:text="@string/pull_to_refresh"
                android:textColor="@color/white"
                android:textSize="16sp" />

            <ImageView
                android:id="@+id/state_iv"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerVertical="true"
                android:layout_marginRight="8dp"
                android:layout_toLeftOf="@id/state_tv"
                android:visibility="gone" />
        </RelativeLayout>
    </RelativeLayout>

</RelativeLayout>

© 著作权归作者所有

lsy999
粉丝 0
博文 110
码字总数 27167
作品 0
程序员
私信 提问
开源项目Actionbar-pulltorefesh的使用

下拉刷新功能 ActionBar-PullToRefresh-master 提供了两套方案: 1. actionbarcompat 使用Android兼容包Compat 功能较弱, 用户体验较差 2. actionbarsherlock(建议使用) 在Fragment中使用Act...

胡文城
2014/05/10
0
0
Android自己写一个高度定制化UI的下拉刷新控件,使用十分简单方便,GitHub最火的开源控件之一

转载自这个控件的git hub地址:https://github.com/xubinhong/PullToRefreshLayout 如果你需要在3分钟之内集成一个下拉刷新控件并且把他的UI随心所欲的定制,那么你来对地方了。 先上效果图 ...

qq_36523667
2018/04/18
0
0
Android 下拉刷新、上拉加载库--BGARefreshLayout

BGARefreshLayout包含多种下拉刷新效果、上拉加载更多、可配置自定义头部广告位 。 效果图: 目前已经实现了四种下拉刷新效果: 新浪微博下拉刷新风格(可设置各种状态是的文本,可设置整个刷...

bingoogolapple
2016/06/22
2.5K
0
Flutter EasyRefresh+ListView+Scoped Model 实现上拉刷新和分页加载

前言: Flutter项目需要实现“上拉刷新和分页加载“的功能,分页可以把大量数据分割成一个个小段,分次加载。这样可以有效避免因为一次load全部数据而导致客户端变慢的问题。在这里我使用Eas...

EmilyWu
07/18
103
0
那些年不容错过的智能下拉刷新加载框架

一些值得学习的几个下拉刷新上拉加载开源库 功能齐全的AnimRefreshRecyclerView 根据列表的不同效果选择不同的布局管理器 根据不同的布局管理器设置分割线: 设置Header和Footer 手动刷新 An...

codeGoogle
2017/09/26
0
0

没有更多内容

加载失败,请刷新页面

加载更多

OpenStack 简介和几种安装方式总结

OpenStack :是一个由NASA和Rackspace合作研发并发起的,以Apache许可证授权的自由软件和开放源代码项目。项目目标是提供实施简单、可大规模扩展、丰富、标准统一的云计算管理平台。OpenSta...

小海bug
昨天
5
0
DDD(五)

1、引言 之前学习了解了DDD中实体这一概念,那么接下来需要了解的就是值对象、唯一标识。值对象,值就是数字1、2、3,字符串“1”,“2”,“3”,值时对象的特征,对象是一个事物的具体描述...

MrYuZixian
昨天
6
0
数据库中间件MyCat

什么是MyCat? 查看官网的介绍是这样说的 一个彻底开源的,面向企业应用开发的大数据库集群 支持事务、ACID、可以替代MySQL的加强版数据库 一个可以视为MySQL集群的企业级数据库,用来替代昂贵...

沉浮_
昨天
6
0
解决Mac下VSCode打开zsh乱码

1.乱码问题 iTerm2终端使用Zsh,并且配置Zsh主题,该主题主题需要安装字体来支持箭头效果,在iTerm2中设置这个字体,但是VSCode里这个箭头还是显示乱码。 iTerm2展示如下: VSCode展示如下: 2...

HelloDeveloper
昨天
7
0
常用物流快递单号查询接口种类及对接方法

目前快递查询接口有两种方式可以对接,一是和顺丰、圆通、中通、天天、韵达、德邦这些快递公司一一对接接口,二是和快递鸟这样第三方集成接口一次性对接多家常用快递。第一种耗费时间长,但是...

程序的小猿
昨天
9
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部