18034727885
2026-06-26 3f97e780654d2709d32fb815d6398440dbfb12c5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
/**
 * @file XListViewHeader.java
 * @create Apr 18, 2012 5:22:27 PM
 * @author Maxwin
 * @description XListView's header
 */
package medusa.theone.waterdroplistview.view;
 
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
 
import medusa.theone.waterdroplistview.R;
import medusa.theone.waterdroplistview.utils.Utils;
 
public class WaterDropListViewHeader extends FrameLayout {
    private LinearLayout mContainer;
    private ProgressBar mProgressBar;
    private WaterDropView mWaterDropView;
    private STATE mState = STATE.normal;
    private IStateChangedListener mStateChangedListener;
 
    private int stretchHeight;
    private  int readyHeight;
    private static final int DISTANCE_BETWEEN_STRETCH_READY = 250;
 
    public enum STATE {
        normal,//正常
        stretch,//准备进行拉伸
        ready,//拉伸到最大位置
        refreshing,//刷新
        end//刷新结束,回滚
    }
 
    public WaterDropListViewHeader(Context context) {
        super(context);
        initView(context);
    }
 
    /**
     * @param context
     * @param attrs
     */
    public WaterDropListViewHeader(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView(context);
    }
 
    private void initView(Context context) {
        mContainer = (LinearLayout) LayoutInflater.from(context).inflate(
                R.layout.waterdroplistview_header, null);
        mProgressBar = (ProgressBar) mContainer.findViewById(R.id.waterdroplist_header_progressbar);
        mWaterDropView = (WaterDropView) mContainer.findViewById(R.id.waterdroplist_waterdrop);
        // 初始情况,设置下拉刷新view高度为0
        LayoutParams lp = new LayoutParams(
                LayoutParams.MATCH_PARENT, 0);
        addView(mContainer, lp);
        initHeight();
    }
 
    private void initHeight(){
 
        mContainer.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                stretchHeight =  mWaterDropView.getHeight();
                readyHeight = stretchHeight + DISTANCE_BETWEEN_STRETCH_READY;
                getViewTreeObserver().removeGlobalOnLayoutListener(this);
            }
        });
 
    }
    /**
     * 修改状态。注:状态的改变与前一个状态以及下拉头高度有关
     *
     * @param state
     */
    public void updateState(STATE state) {
        if (state == mState) return;
        STATE oldState = mState;
        mState = state;
        if (mStateChangedListener != null) {
            mStateChangedListener.notifyStateChanged(oldState, mState);
        }
 
        switch (mState) {
            case normal:
                handleStateNormal();
                break;
            case stretch:
                handleStateStretch();
                break;
            case ready:
                handleStateReady();
                break;
            case refreshing:
                handleStateRefreshing();
                break;
            case end:
                handleStateEnd();
                break;
            default:
        }
    }
 
    /**
     * 处理处于normal状态的值
     */
    private void handleStateNormal() {
        mWaterDropView.setVisibility(View.VISIBLE);
        mProgressBar.setVisibility(View.GONE);
        mContainer.setGravity(Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL);
    }
 
    /**
     * 处理水滴拉伸状态
     */
    private void handleStateStretch() {
        mWaterDropView.setVisibility(View.VISIBLE);
        mProgressBar.setVisibility(View.GONE);
        mContainer.setGravity(Gravity.TOP | Gravity.CENTER_HORIZONTAL);
    }
 
    /**
     * 处理水滴ready状态,回弹效果
     */
    private void handleStateReady() {
        mWaterDropView.setVisibility(View.VISIBLE);
        mProgressBar.setVisibility(View.GONE);
        Animator shrinkAnimator = mWaterDropView.createAnimator();
        shrinkAnimator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                //回弹结束后即进入refreshing状态
                updateState(STATE.refreshing);
            }
        });
        shrinkAnimator.start();//开始回弹
    }
 
    /**
     * 处理正在进行刷新状态
     */
    private void  handleStateRefreshing() {
        mWaterDropView.setVisibility(View.GONE);
        mProgressBar.setVisibility(View.VISIBLE);
    }
 
    /**
     * 处理刷新完毕状态
     */
    private void handleStateEnd() {
        mWaterDropView.setVisibility(View.GONE);
        mProgressBar.setVisibility(View.GONE);
    }
 
    public void setVisiableHeight(int height) {
        if (height < 0)
            height = 0;
        LayoutParams lp = (LayoutParams) mContainer
                .getLayoutParams();
        lp.height = height;
        mContainer.setLayoutParams(lp);
        //通知水滴进行更新
        if(mState == STATE.stretch){
            float pullOffset = (float) Utils.mapValueFromRangeToRange(height, stretchHeight, readyHeight, 0, 1);
            if(pullOffset < 0 || pullOffset >1){
                throw new IllegalArgumentException("pullOffset should between 0 and 1!"+mState+" "+height);
            }
            Log.e("pullOffset", "pullOffset:" + pullOffset);
            mWaterDropView.updateComleteState(pullOffset);
        }
 
    }
 
 
    public int getVisiableHeight() {
        return mContainer.getHeight();
    }
 
    public STATE getCurrentState() {
        return mState;
    }
 
    public int getStretchHeight() {
        return stretchHeight;
    }
 
    public int getReadyHeight() {
        return readyHeight;
    }
 
    public void setStateChangedListener(IStateChangedListener l) {
        mStateChangedListener = l;
    }
 
    public interface IStateChangedListener {
        public void notifyStateChanged(STATE oldState, STATE newState);
    }
}