定位

代码!

<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" 

  android:orientation="vertical" > 

 

  <com.example.pulldown.PullDownScrollView 

      android:id="@+id/refresh_root" 

      android:layout_width="fill_parent" 

      android:layout_height="0dip" 

      android:layout_weight="1" 

      android:background="#161616" 

      android:orientation="vertical" > 

 

      <ScrollView 

          android:id="@+id/scrollview" 

          android:layout_width="fill_parent" 

          android:layout_height="wrap_content" 

          android:scrollbars="none" > 

 

          <LinearLayout 

              android:id="@+id/mainView" 

              android:layout_width="fill_parent" 

              android:layout_height="wrap_content" 

              android:background="#1f1f1f" 

              android:orientation="vertical" > 

 

              <!-- 自已的布局 --> 

 

              <TextView 

                  android:layout_width="match_parent" 

                  android:layout_height="wrap_content" 

                  android:layout_marginTop="10dip" 

                  android:gravity="center" 

                  android:text="@string/hello_world" 

                  android:textColor="@android:color/white" 

                  android:textSize="18sp" /> 

 

              <TextView 

                  android:layout_width="match_parent" 

                  android:layout_height="wrap_content" 

                  android:layout_marginTop="10dip" 

                  android:gravity="center" 

                  android:text="@string/hello_world" 

                  android:textColor="@android:color/white" 

                  android:textSize="18sp" /> 

 

              <TextView 

                  android:layout_width="match_parent" 

                  android:layout_height="wrap_content" 

                  android:layout_marginTop="10dip" 

                  android:gravity="center" 

                  android:text="@string/hello_world" 

                  android:textColor="@android:color/white" 

                  android:textSize="18sp" /> 

 

              <TextView 

                  android:layout_width="match_parent" 

                  android:layout_height="wrap_content" 

                  android:layout_marginTop="10dip" 

                  android:gravity="center" 

                  android:text="@string/hello_world" 

                  android:textColor="@android:color/white" 

                  android:textSize="18sp" /> 

          </LinearLayout> 

      </ScrollView> 

  </com.example.pulldown.PullDownScrollView> 

 

lt;/LinearLayout> 

2.UI使用:

  首先,Activity实现接口:

implements RefreshListener

部分代码如下:

Java代码  收藏代码

  package com.example.pulldown; 

 

import com.example.pulldown.PullDownScrollView.RefreshListener; 

 

import android.os.Bundle; 

import android.os.Handler; 

import android.app.Activity; 

import android.view.Menu; 

 

public class MainActivity extends Activity implements RefreshListener{ 

    private PullDownScrollView mPullDownScrollView; 

    @Override 

    protected void onCreate(Bundle savedInstanceState) { 

        super.onCreate(savedInstanceState); 

        setContentView(R.layout.activity_main); 

         

        mPullDownScrollView = (PullDownScrollView) findViewById(R.id.refresh_root);   

        mPullDownScrollView.setRefreshListener(this);   

        mPullDownScrollView.setPullDownElastic(new PullDownElasticImp(this));   

    } 

    @Override   

    public void onRefresh(PullDownScrollView view) {   

        new Handler().postDelayed(new Runnable() {   

               

            @Override   

            public void run() {   

                // TODO Auto-generated method stub   

                mPullDownScrollView.finishRefresh("上次刷新时间:12:23");   

            }   

        }, 2000);   

    }   

    @Override 

    public boolean onCreateOptionsMenu(Menu menu) { 

        // Inflate the menu; this adds items to the action bar if it is present. 

        getMenuInflater().inflate(R.menu.activity_main, menu); 

        return true; 

    } 

 

3.再来看看控件代码:

Java代码  收藏代码

import android.content.Context; 

import android.util.AttributeSet; 

import android.view.MotionEvent; 

import android.view.View; 

import android.view.animation.LinearInterpolator; 

import android.view.animation.RotateAnimation; 

import android.widget.AbsListView; 

import android.widget.LinearLayout; 

import android.widget.ScrollView; 

 

 

/**

* @author xwangly@163.com

* @date 2013-7-9

*/ 

public class PullDownScrollView extends LinearLayout { 

 

    private static final String TAG = "PullDownScrollView"; 

 

    private int refreshTargetTop = -60; 

    private int headContentHeight; 

 

    private RefreshListener refreshListener; 

 

    private RotateAnimation animation; 

    private RotateAnimation reverseAnimation; 

     

    private final static int RATIO = 2; 

    private int preY = 0; 

    private boolean isElastic = false; 

    private int startY; 

    private int state; 

     

    private String note_release_to_refresh = "松开更新"; 

    private String note_pull_to_refresh = "下拉刷新"; 

    private String note_refreshing = "正在更新..."; 

     

    private IPullDownElastic mElastic; 

     

 

    public PullDownScrollView(Context context) { 

        super(context); 

        init(); 

 

    } 

 

    public PullDownScrollView(Context context, AttributeSet attrs) { 

        super(context, attrs); 

        init(); 

    } 

 

    private void init() { 

        animation = new RotateAnimation(0, -180, 

                RotateAnimation.RELATIVE_TO_SELF, 0.5f, 

                RotateAnimation.RELATIVE_TO_SELF, 0.5f); 

        animation.setInterpolator(new LinearInterpolator()); 

        animation.setDuration(250); 

        animation.setFillAfter(true); 

 

        reverseAnimation = new RotateAnimation(-180, 0, 

                RotateAnimation.RELATIVE_TO_SELF, 0.5f, 

                RotateAnimation.RELATIVE_TO_SELF, 0.5f); 

        reverseAnimation.setInterpolator(new LinearInterpolator()); 

        reverseAnimation.setDuration(200); 

        reverseAnimation.setFillAfter(true); 

    } 

    /**

    * 刷新监听

    * @param listener

    */ 

    public void setRefreshListener(RefreshListener listener) { 

        this.refreshListener = listener; 

    } 

    /**

    * 下拉布局

    * @param elastic

    */ 

    public void setPullDownElastic(IPullDownElastic elastic) { 

        mElastic = elastic; 

         

        headContentHeight = mElastic.getElasticHeight(); 

        refreshTargetTop = - headContentHeight; 

        LayoutParams lp = new LinearLayout.LayoutParams( 

                LayoutParams.FILL_PARENT, headContentHeight); 

        lp.topMargin = refreshTargetTop; 

        addView(mElastic.getElasticLayout(), 0, lp); 

    } 

     

    /**

    * 设置更新提示语

    * @param pullToRefresh 下拉刷新提示语

    * @param releaseToRefresh 松开刷新提示语

    * @param refreshing 正在刷新提示语

    */ 

    public void setRefreshTips(String pullToRefresh, String releaseToRefresh, String refreshing) { 

        note_pull_to_refresh = pullToRefresh; 

        note_release_to_refresh = releaseToRefresh; 

        note_refreshing = refreshing; 

    } 

    /*

    * 该方法一般和ontouchEvent 一起用 (non-Javadoc)

    * 

    * @see

    * android.view.ViewGroup#onInterceptTouchEvent(android.view.MotionEvent)

    */ 

    @Override 

    public boolean onInterceptTouchEvent(MotionEvent ev) { 

        Logger.d(TAG, "onInterceptTouchEvent"); 

        printMotionEvent(ev); 

        if (ev.getAction() == MotionEvent.ACTION_DOWN) { 

            preY = (int) ev.getY(); 

        } 

        if (ev.getAction() == MotionEvent.ACTION_MOVE) { 

 

            Logger.d(TAG, "isElastic:" + isElastic + " canScroll:"+ canScroll() + " ev.getY() - preY:"+(ev.getY() - preY)); 

            if (!isElastic && canScroll() 

                    && (int) ev.getY() - preY >= headContentHeight / (3*RATIO) 

                    && refreshListener != null && mElastic != null) { 

 

                isElastic = true; 

                startY = (int) ev.getY(); 

                Logger.i(TAG, "在move时候记录下位置startY:" + startY); 

                return true; 

            } 

 

        } 

        return super.onInterceptTouchEvent(ev); 

    } 

 

    @Override 

    public boolean onTouchEvent(MotionEvent event) { 

        Logger.d(TAG, "onTouchEvent"); 

        printMotionEvent(event); 

        handleHeadElastic(event); 

        return super.onTouchEvent(event); 

    } 

 

    private void handleHeadElastic(MotionEvent event) { 

        if (refreshListener != null && mElastic != null) { 

            switch (event.getAction()) { 

            case MotionEvent.ACTION_DOWN: 

                Logger.i(TAG, "down"); 

                break; 

            case MotionEvent.ACTION_UP: 

 

                Logger.i(TAG, "up"); 

                if (state != IPullDownElastic.REFRESHING && isElastic) { 

                     

                    if (state == IPullDownElastic.DONE) { 

                        // 什么都不做 

                        setMargin(refreshTargetTop); 

                    } 

                    if (state == IPullDownElastic.PULL_To_REFRESH) { 

                        state = IPullDownElastic.DONE; 

                        setMargin(refreshTargetTop); 

                        changeHeaderViewByState(state, false); 

                        Logger.i(TAG, "由下拉刷新状态,到done状态"); 

                    } 

                    if (state == IPullDownElastic.RELEASE_To_REFRESH) { 

                        state = IPullDownElastic.REFRESHING; 

                        setMargin(0); 

                        changeHeaderViewByState(state, false); 

                        onRefresh(); 

                        Logger.i(TAG, "由松开刷新状态,到done状态"); 

                    } 

 

                } 

                isElastic = false; 

                break; 

            case MotionEvent.ACTION_MOVE: 

                Logger.i(TAG, "move"); 

                int tempY = (int) event.getY(); 

                 

                if (state != IPullDownElastic.REFRESHING && isElastic) { 

                    // 可以松手去刷新了 

                    if (state == IPullDownElastic.RELEASE_To_REFRESH) { 

                        if (((tempY - startY) / RATIO < headContentHeight) 

                                && (tempY - startY) > 0) { 

                            state = IPullDownElastic.PULL_To_REFRESH; 

                            changeHeaderViewByState(state, true); 

                            Logger.i(TAG, "由松开刷新状态转变到下拉刷新状态"); 

                        } else if (tempY - startY <= 0) { 

                            state = IPullDownElastic.DONE; 

                            changeHeaderViewByState(state, false); 

                            Logger.i(TAG, "由松开刷新状态转变到done状态"); 

                        } 

                    } 

                    if (state == IPullDownElastic.DONE) { 

                        if (tempY - startY > 0) { 

                            state = IPullDownElastic.PULL_To_REFRESH; 

                            changeHeaderViewByState(state, false); 

                        } 

                    } 

                    if (state == IPullDownElastic.PULL_To_REFRESH) { 

                        // 下拉到可以进入RELEASE_TO_REFRESH的状态 

                        if ((tempY - startY) / RATIO >= headContentHeight) { 

                            state = IPullDownElastic.RELEASE_To_REFRESH; 

                            changeHeaderViewByState(state, false); 

                            Logger.i(TAG, "由done或者下拉刷新状态转变到松开刷新"); 

                        } else if (tempY - startY <= 0) { 

                            state = IPullDownElastic.DONE; 

                            changeHeaderViewByState(state, false); 

                            Logger.i(TAG, "由DOne或者下拉刷新状态转变到done状态"); 

                        } 

                    } 

                    if (tempY - startY > 0) { 

                        setMargin((tempY - startY)/2 + refreshTargetTop); 

                    } 

                } 

                break; 

            } 

        } 

    } 

     

    /**

    * 

    */ 

    private void setMargin(int top) { 

        LinearLayout.LayoutParams lp = (LayoutParams) mElastic.getElasticLayout() 

                .getLayoutParams(); 

        lp.topMargin = top; 

        // 修改后刷新 

        mElastic.getElasticLayout().setLayoutParams(lp); 

        mElastic.getElasticLayout().invalidate(); 

    } 

 

    private void changeHeaderViewByState(int state, boolean isBack) { 

 

        mElastic.changeElasticState(state, isBack); 

        switch (state) { 

        case IPullDownElastic.RELEASE_To_REFRESH: 

            mElastic.showArrow(View.VISIBLE); 

            mElastic.showProgressBar(View.GONE); 

            mElastic.showLastUpdate(View.VISIBLE); 

            mElastic.setTips(note_release_to_refresh); 

 

            mElastic.clearAnimation(); 

            mElastic.startAnimation(animation); 

            Logger.i(TAG, "当前状态,松开刷新"); 

            break; 

        case IPullDownElastic.PULL_To_REFRESH: 

            mElastic.showArrow(View.VISIBLE); 

            mElastic.showProgressBar(View.GONE); 

            mElastic.showLastUpdate(View.VISIBLE); 

            mElastic.setTips(note_pull_to_refresh); 

 

            mElastic.clearAnimation(); 

 

            // 是由RELEASE_To_REFRESH状态转变来的 

            if (isBack) { 

                mElastic.startAnimation(reverseAnimation); 

            } 

            Logger.i(TAG, "当前状态,下拉刷新"); 

            break; 

        case IPullDownElastic.REFRESHING: 

            mElastic.showArrow(View.GONE); 

            mElastic.showProgressBar(View.VISIBLE); 

            mElastic.showLastUpdate(View.GONE); 

            mElastic.setTips(note_refreshing); 

 

            mElastic.clearAnimation(); 

            Logger.i(TAG, "当前状态,正在刷新..."); 

            break; 

        case IPullDownElastic.DONE: 

            mElastic.showProgressBar(View.GONE); 

            mElastic.clearAnimation(); 

//            arrowImageView.setImageResource(R.drawable.goicon); 

            // tipsTextview.setText("下拉刷新"); 

            // lastUpdatedTextView.setVisibility(View.VISIBLE); 

            Logger.i(TAG, "当前状态,done"); 

            break; 

        } 

    } 

 

    private void onRefresh() { 

        // downTextView.setVisibility(View.GONE); 

//        scroller.startScroll(0, i, 0, 0 - i); 

//        invalidate(); 

        if (refreshListener != null) { 

            refreshListener.onRefresh(this); 

        } 

    } 

 

    /**

    * 

    */ 

    @Override 

    public void computeScroll() { 

//        if (scroller.computeScrollOffset()) { 

//            int i = this.scroller.getCurrY(); 

//            LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) this.refreshView 

//                    .getLayoutParams(); 

//            int k = Math.max(i, refreshTargetTop); 

//            lp.topMargin = k; 

//            this.refreshView.setLayoutParams(lp); 

//            this.refreshView.invalidate(); 

//            invalidate(); 

//        } 

    } 

 

    /**

    * 结束刷新事件,UI刷新完成后必须回调此方法

    * @param text 一般传入:“上次更新时间:12:23”

    */ 

    public void finishRefresh(String text) { 

        if (mElastic == null) { 

            Logger.d(TAG, "finishRefresh mElastic:" + mElastic); 

            return; 

        } 

        state = IPullDownElastic.DONE; 

        mElastic.setLastUpdateText(text); 

        changeHeaderViewByState(state,false); 

        Logger.i(TAG, "执行了=====finishRefresh"); 

 

        mElastic.showArrow(View.VISIBLE); 

        mElastic.showLastUpdate(View.VISIBLE); 

        setMargin(refreshTargetTop); 

//        scroller.startScroll(0, i, 0, refreshTargetTop); 

//        invalidate(); 

    } 

 

    private boolean canScroll() { 

        View childView; 

        if (getChildCount() > 1) { 

            childView = this.getChildAt(1); 

            if (childView instanceof AbsListView) { 

                int top = ((AbsListView) childView).getChildAt(0).getTop(); 

                int pad = ((AbsListView) childView).getListPaddingTop(); 

                if ((Math.abs(top - pad)) < 3 

                        && ((AbsListView) childView).getFirstVisiblePosition() == 0) { 

                    return true; 

                } else { 

                    return false; 

                } 

            } else if (childView instanceof ScrollView) { 

                if (((ScrollView) childView).getScrollY() == 0) { 

                    return true; 

                } else { 

                    return false; 

                } 

            } 

 

        } 

        return canScroll(this); 

    } 

     

    /**

    * 子类重写此方法可以兼容其它的子控件,目前只兼容AbsListView和ScrollView

    * @param view

    * @return

    */ 

    public boolean canScroll(PullDownScrollView view) { 

        return false; 

    } 

 

    private void printMotionEvent(MotionEvent event) { 

        switch (event.getAction()) { 

        case MotionEvent.ACTION_DOWN: 

            Logger.d(TAG, "down"); 

            break; 

        case MotionEvent.ACTION_MOVE: 

            Logger.d(TAG, "move"); 

            break; 

        case MotionEvent.ACTION_UP: 

            Logger.d(TAG, "up"); 

        default: 

            break; 

        } 

    } 

    /**

    * 刷新监听接口

    */ 

    public interface RefreshListener { 

        public void onRefresh(PullDownScrollView view); 

    } 

 

4.接口:

Java代码  收藏代码

import android.view.View; 

import android.view.animation.Animation; 

 

/**

* @author xwangly@163.com

* @date 2013-7-10

* 下拉控件接口

*/ 

public interface IPullDownElastic { 

    public final static int RELEASE_To_REFRESH = 0; 

    public final static int PULL_To_REFRESH = 1; 

    public final static int REFRESHING = 2; 

    public final static int DONE = 3; 

 

    public View getElasticLayout(); 

 

    public int getElasticHeight(); 

 

    public void showArrow(int visibility); 

 

    public void startAnimation(Animation animation); 

 

    public void clearAnimation(); 

 

    public void showProgressBar(int visibility); 

 

    public void setTips(String tips); 

 

    public void showLastUpdate(int visibility); 

 

    public void setLastUpdateText(String text); 

     

    /**

    * 可以不用实现此方法,PullDownScrollView会处理ElasticLayout布局中的状态 

    * 如果需要特殊处理,可以实现此方法进行处理

    * 

    * @param state  @see RELEASE_To_REFRESH

    * @param isBack 是否是松开回退

    */ 

    public void changeElasticState(int state, boolean isBack); 

 

5.默认实现:

Java代码  收藏代码

import android.content.Context; 

import android.view.LayoutInflater; 

import android.view.View; 

import android.view.animation.Animation; 

import android.widget.ImageView; 

import android.widget.ProgressBar; 

import android.widget.TextView; 

 

 

/**

* @author xwangly@163.com

* @date  2013-7-10

* 默认下拉控件布局实现

*/ 

public class PullDownElasticImp implements IPullDownElastic { 

    private View refreshView; 

    private ImageView arrowImageView; 

    private int headContentHeight; 

    private ProgressBar progressBar; 

    private TextView tipsTextview; 

    private TextView lastUpdatedTextView; 

     

    private Context mContext; 

    public PullDownElasticImp(Context context) { 

        mContext = context; 

        init(); 

    } 

     

 

    private void init() { 

        // 刷新视图顶端的的view 

        refreshView = LayoutInflater.from(mContext).inflate( 

                R.layout.refresh_top_item, null); 

 

        // 指示器view 

        arrowImageView = (ImageView) refreshView 

                .findViewById(R.id.head_arrowImageView); 

        // 刷新bar 

        progressBar = (ProgressBar) refreshView 

                .findViewById(R.id.head_progressBar); 

        // 下拉显示text 

        tipsTextview = (TextView) refreshView.findViewById(R.id.refresh_hint); 

        // 下来显示时间 

        lastUpdatedTextView = (TextView) refreshView 

                .findViewById(R.id.refresh_time); 

 

        headContentHeight = Utils.dip2px(mContext, 50); 

    } 

 

    /**

    * @return

    * 

    */ 

    @Override 

    public View getElasticLayout() { 

        return refreshView; 

    } 

 

    /**

    * @return

    * 

    */ 

    @Override 

    public int getElasticHeight() { 

        return headContentHeight; 

    } 

 

    /**

    * @param show

    * 

    */ 

    @Override 

    public void showArrow(int visibility) { 

        arrowImageView.setVisibility(visibility); 

    } 

 

    /**

    * @param animation

    * 

    */ 

    @Override 

    public void startAnimation(Animation animation) { 

        arrowImageView.startAnimation(animation); 

    } 

 

    /**

    * 

    * 

    */ 

    @Override 

    public void clearAnimation() { 

        arrowImageView.clearAnimation(); 

    } 

 

    /**

    * @param show

    * 

    */ 

    @Override 

    public void showProgressBar(int visibility) { 

        progressBar.setVisibility(visibility); 

    } 

 

    /**

    * @param tips

    * 

    */ 

    @Override 

    public void setTips(String tips) { 

        tipsTextview.setText(tips); 

    } 

 

    /**

    * @param show

    * 

    */ 

    @Override 

    public void showLastUpdate(int visibility) { 

        lastUpdatedTextView.setVisibility(visibility); 

    } 

 

    /**

    * @param text

    * 

    */ 

    public void setLastUpdateText(String text) { 

        lastUpdatedTextView.setText(text); 

    } 

 

 

    /**

    * @param state

    * @param isBack

    * 

    */ 

    @Override 

    public void changeElasticState(int state, boolean isBack) { 

        // TODO Auto-generated method stub 

         

    } 

 

6.默认实现的布局:

Java代码  收藏代码

<?xml version="1.0" encoding="utf-8"?> 

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 

    android:layout_width="fill_parent" 

    android:layout_height="-50.0dip" 

    android:orientation="vertical" > 

 

    <LinearLayout 

        android:layout_width="fill_parent" 

        android:layout_height="0.0dip" 

        android:layout_weight="1.0" 

        android:gravity="center" 

        android:orientation="horizontal" > 

 

        <!-- 箭头图像、进度条 --> 

 

        <FrameLayout 

            android:layout_width="wrap_content" 

            android:layout_height="wrap_content" 

            android:layout_alignParentLeft="true" 

            android:layout_centerVertical="true" 

            android:layout_marginLeft="30dip" > 

 

            <!-- 箭头 --> 

 

            <ImageView 

                android:id="@+id/head_arrowImageView" 

                android:layout_width="wrap_content" 

                android:layout_height="wrap_content" 

                android:layout_gravity="center" 

                android:src="@drawable/goicon" /> 

 

            <!-- 进度条 --> 

 

            <ProgressBar 

                android:id="@+id/head_progressBar" 

                style="@android:style/Widget.ProgressBar.Small.Inverse" 

                android:layout_width="wrap_content" 

                android:layout_height="wrap_content" 

                android:layout_gravity="center" 

                android:visibility="gone" /> 

        </FrameLayout> 

 

        <LinearLayout 

            android:layout_width="fill_parent" 

            android:layout_height="fill_parent" 

            android:gravity="center" 

            android:orientation="vertical" > 

 

            <!-- 提示 --> 

 

            <TextView 

                android:id="@+id/refresh_hint" 

                android:layout_width="wrap_content" 

                android:layout_height="wrap_content" 

                android:text="下拉刷新" 

                android:textColor="#f2f2f2" 

                android:textSize="16sp" /> 

 

            <!-- 最近更新 --> 

 

            <TextView 

                android:id="@+id/refresh_time" 

                android:layout_width="wrap_content" 

                android:layout_height="wrap_content" 

                android:text="上次更新" 

                android:textColor="#b89766" 

                android:textSize="10sp" /> 

        </LinearLayout> 

    </LinearLayout> 

 

</LinearLayout> 

6.图片资源:

@drawable/goicon

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 157,767评论 24 688
  • mean to add the formatted="false" attribute?.[ 46% 47325/...
    ProZoom阅读 1,539评论 0 3
  • 你突然的热络,莫名其妙 我积极的应承,带着傻笑 你说晚安咯,月亮已经睡着了 我说好好好,愿你睡个好觉 然后我又说了...
    莉莉安的斑马阅读 118评论 0 0
  • 作为一名金融民工,米粒深知坚守岗位的重要性,所以,领导说,初一过来上班的时候,米粒几乎是毫不犹豫地答应了。 也不过...
    财女有钱途阅读 355评论 0 0
  • 仅此以纪念我出生的第一天,我要做的所有事情就是,回报父母,然后找到自己,抓住自己,做回自己。理清了自己,也希望从今...
    会编码的小妮子阅读 31评论 0 0