(textView);
75 | }
76 |
77 | /**
78 | * Stops the jumping animation and frees up the animations.
79 | */
80 | public void stopJumping() {
81 | for (JumpingBeansSpan bean : jumpingBeans) {
82 | if (bean != null) {
83 | bean.teardown();
84 | }
85 | }
86 |
87 | TextView tv = textView.get();
88 | if (tv != null) {
89 | CharSequence text = tv.getText();
90 | if (text instanceof Spanned) {
91 | CharSequence cleanText = removeJumpingBeansSpans((Spanned) text);
92 | tv.setText(cleanText);
93 | }
94 | }
95 | }
96 |
97 | private static CharSequence removeJumpingBeansSpans(Spanned text) {
98 | SpannableStringBuilder sbb = new SpannableStringBuilder(text.toString());
99 | Object[] spans = text.getSpans(0, text.length(), Object.class);
100 | for (Object span : spans) {
101 | if (!(span instanceof JumpingBeansSpan)) {
102 | sbb.setSpan(span, text.getSpanStart(span),
103 | text.getSpanEnd(span), text.getSpanFlags(span));
104 | }
105 | }
106 | return sbb;
107 | }
108 |
109 | /**
110 | * Builder class for {@link net.frakbot.jumpingbeans.JumpingBeans} objects.
111 | *
112 | * Provides a way to set the fields of a {@link JumpingBeans} and generate
113 | * the desired jumping beans effect. With this builder you can easily append
114 | * a Hangouts-style trio of jumping suspension points to any TextView, or
115 | * apply the effect to any other subset of a TextView's text.
116 | *
117 | * Example:
118 | *
119 | *
120 | * JumpingBeans jumpingBeans = new JumpingBeans.Builder()
121 | * .appendJumpingDots(myTextView)
122 | * .setLoopDuration(1500)
123 | * .build();
124 | *
125 | */
126 | public static class Builder {
127 |
128 | private int startPos, endPos;
129 | private float animRange = DEFAULT_ANIMATION_DUTY_CYCLE;
130 | private int loopDuration = DEFAULT_LOOP_DURATION;
131 | private int waveCharDelay = -1;
132 | private CharSequence text;
133 | private TextView textView;
134 | private boolean wave;
135 |
136 | /**
137 | * Appends three jumping dots to the end of a TextView text.
138 | *
139 | * This implies that the animation will by default be a wave.
140 | *
141 | * If the TextView has no text, the resulting TextView text will
142 | * consist of the three dots only.
143 | *
144 | * The TextView text is cached to the current value at
145 | * this time and set again in the {@link #build()} method, so any
146 | * change to the TextView text done in the meantime will be lost.
147 | * This means that you should do all changes to the TextView text
148 | * before you begin using this builder.
149 | *
150 | * Call the {@link #build()} method once you're done to get the
151 | * resulting {@link net.frakbot.jumpingbeans.JumpingBeans}.
152 | *
153 | * @param textView The TextView to append the dots to
154 | * @see #setIsWave(boolean)
155 | */
156 | public Builder appendJumpingDots(TextView textView) {
157 | if (textView == null) {
158 | throw new NullPointerException("The textView must not be null");
159 | }
160 |
161 | CharSequence text = !TextUtils.isEmpty(textView.getText()) ? textView.getText() : "";
162 | if (text.length() > 0 && text.subSequence(text.length() - 1, text.length()).equals("…")) {
163 | text = text.subSequence(0, text.length() - 1);
164 | }
165 |
166 | if (text.length() < 3 || !TextUtils.equals(text.subSequence(text.length() - 3, text.length()), "...")) {
167 | text = new SpannableStringBuilder(text).append("..."); // Preserve spans in original text
168 | }
169 |
170 | this.text = text;
171 | this.wave = true;
172 | this.textView = textView;
173 | this.startPos = this.text.length() - 3;
174 | this.endPos = this.text.length();
175 | return this;
176 | }
177 |
178 | /**
179 | * Appends three jumping dots to the end of a TextView text.
180 | *
181 | * This implies that the animation will by default be a wave.
182 | *
183 | * If the TextView has no text, the resulting TextView text will
184 | * consist of the three dots only.
185 | *
186 | * The TextView text is cached to the current value at
187 | * this time and set again in the {@link #build()} method, so any
188 | * change to the TextView text done in the meantime will be lost.
189 | * This means that you should do all changes to the TextView text
190 | * before you begin using this builder.
191 | *
192 | * Call the {@link #build()} method once you're done to get the
193 | * resulting {@link net.frakbot.jumpingbeans.JumpingBeans}.
194 | *
195 | * @param textView The TextView whose text is to be animated
196 | * @param startPos The position of the first character to animate
197 | * @param endPos The position after the one the animated range ends at
198 | * (just like in String#substring())
199 | * @see #setIsWave(boolean)
200 | */
201 | public Builder makeTextJump(TextView textView, int startPos, int endPos) {
202 | if (textView == null || textView.getText() == null) {
203 | throw new NullPointerException("The textView and its text must not be null");
204 | }
205 |
206 | if (endPos < startPos) {
207 | throw new IllegalArgumentException("The start position must be smaller than the end position");
208 | }
209 |
210 | if (startPos < 0) {
211 | throw new IndexOutOfBoundsException("The start position must be non-negative");
212 | }
213 |
214 | this.text = textView.getText();
215 | if (endPos > text.length()) {
216 | throw new IndexOutOfBoundsException("The end position must be smaller than the text length");
217 | }
218 |
219 | this.wave = true;
220 | this.textView = textView;
221 | this.startPos = startPos;
222 | this.endPos = endPos;
223 | return this;
224 | }
225 |
226 | /**
227 | * Sets the fraction of the animation loop time spent actually animating.
228 | * The rest of the time will be spent "resting".
229 | * The default value is
230 | * {@link net.frakbot.jumpingbeans.JumpingBeans#DEFAULT_ANIMATION_DUTY_CYCLE}.
231 | *
232 | * @param animatedRange The fraction of the animation loop time spent
233 | * actually animating the characters
234 | */
235 | public Builder setAnimatedDutyCycle(float animatedRange) {
236 | if (animatedRange <= 0f || animatedRange > 1f) {
237 | throw new IllegalArgumentException("The animated range must be in the (0, 1] range");
238 | }
239 | this.animRange = animatedRange;
240 | return this;
241 | }
242 |
243 | /**
244 | * Sets the jumping loop duration. The default value is
245 | * {@link net.frakbot.jumpingbeans.JumpingBeans#DEFAULT_LOOP_DURATION}.
246 | *
247 | * @param loopDuration The jumping animation loop duration, in milliseconds
248 | */
249 | public Builder setLoopDuration(int loopDuration) {
250 | if (loopDuration < 1) {
251 | throw new IllegalArgumentException("The loop duration must be bigger than zero");
252 | }
253 | this.loopDuration = loopDuration;
254 | return this;
255 | }
256 |
257 | /**
258 | * Sets the delay for starting the animation of every single dot over the
259 | * start of the previous one, in milliseconds. The default value is
260 | * the loop length divided by three times the number of character animated
261 | * by this instance of JumpingBeans.
262 | *
263 | * Only has a meaning when the animation is a wave.
264 | *
265 | * @param waveCharOffset The start delay for the animation of every single
266 | * character over the previous one, in milliseconds
267 | * @see #setIsWave(boolean)
268 | */
269 | public Builder setWavePerCharDelay(int waveCharOffset) {
270 | if (waveCharOffset < 0) {
271 | throw new IllegalArgumentException("The wave char offset must be non-negative");
272 | }
273 | this.waveCharDelay = waveCharOffset;
274 | return this;
275 | }
276 |
277 | /**
278 | * Sets a flag that determines if the characters will jump in a wave
279 | * (i.e., with a delay between each other) or all at the same
280 | * time.
281 | *
282 | * @param wave If true, the animation is going to be a wave; if
283 | * false, all characters will jump ay the same time
284 | * @see #setWavePerCharDelay(int)
285 | */
286 | public Builder setIsWave(boolean wave) {
287 | this.wave = wave;
288 | return this;
289 | }
290 |
291 | /**
292 | * Combine all of the options that have been set and return a new
293 | * {@link net.frakbot.jumpingbeans.JumpingBeans} instance.
294 | *
295 | * Remember to call the {@link #stopJumping()} method once you're done
296 | * using the JumpingBeans (that is, when you detach the TextView from
297 | * the view tree, you hide it, or the parent Activity/Fragment goes in
298 | * the paused status). This will allow to release the animations and
299 | * free up memory and CPU that would be otherwise wasted.
300 | */
301 | public JumpingBeans build() {
302 | SpannableStringBuilder sbb = new SpannableStringBuilder(text);
303 | JumpingBeansSpan[] jumpingBeans;
304 | if (!wave) {
305 | jumpingBeans = new JumpingBeansSpan[]{new JumpingBeansSpan(textView, loopDuration, 0, 0, animRange)};
306 | sbb.setSpan(jumpingBeans[0], startPos, endPos, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
307 | } else {
308 | if (waveCharDelay == -1) {
309 | waveCharDelay = loopDuration / (3 * (endPos - startPos));
310 | }
311 |
312 | jumpingBeans = new JumpingBeansSpan[endPos - startPos];
313 | for (int pos = startPos; pos < endPos; pos++) {
314 | JumpingBeansSpan jumpingBean =
315 | new JumpingBeansSpan(textView, loopDuration, pos - startPos, waveCharDelay, animRange);
316 | sbb.setSpan(jumpingBean, pos, pos + 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
317 | jumpingBeans[pos - startPos] = jumpingBean;
318 | }
319 | }
320 |
321 | textView.setText(sbb);
322 | return new JumpingBeans(jumpingBeans, textView);
323 | }
324 | }
325 | }
326 |
--------------------------------------------------------------------------------
/src/com/socks/autoload/JumpingBeansSpan.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 Frakbot (Sebastiano Poggi and Francesco Pontillo)
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.socks.autoload;
18 |
19 | import android.animation.TimeInterpolator;
20 | import android.animation.ValueAnimator;
21 | import android.os.Build;
22 | import android.text.TextPaint;
23 | import android.text.style.SuperscriptSpan;
24 | import android.util.Log;
25 | import android.view.View;
26 | import android.widget.TextView;
27 |
28 | import java.lang.ref.WeakReference;
29 |
30 | /*package*/ final class JumpingBeansSpan extends SuperscriptSpan implements ValueAnimator.AnimatorUpdateListener {
31 |
32 | private ValueAnimator jumpAnimator;
33 | private WeakReference textView;
34 | private int shift;
35 | private int delay;
36 | private int loopDuration;
37 | private float animatedRange;
38 |
39 | public JumpingBeansSpan(TextView textView, int loopDuration, int position, int waveCharOffset,
40 | float animatedRange) {
41 | this.textView = new WeakReference<>(textView);
42 | this.delay = waveCharOffset * position;
43 | this.loopDuration = loopDuration;
44 | this.animatedRange = animatedRange;
45 | }
46 |
47 | @Override
48 | public void updateMeasureState(TextPaint tp) {
49 | initIfNecessary(tp);
50 | tp.baselineShift = shift;
51 | }
52 |
53 | @Override
54 | public void updateDrawState(TextPaint tp) {
55 | initIfNecessary(tp);
56 | tp.baselineShift = shift;
57 | }
58 |
59 | private void initIfNecessary(TextPaint tp) {
60 | if (jumpAnimator != null) {
61 | return;
62 | }
63 |
64 | shift = (int) tp.ascent() / 2;
65 | jumpAnimator = ValueAnimator.ofInt(0, shift, 0);
66 | jumpAnimator
67 | .setDuration(loopDuration)
68 | .setStartDelay(delay);
69 | jumpAnimator.setInterpolator(new JumpInterpolator(animatedRange));
70 | jumpAnimator.setRepeatCount(ValueAnimator.INFINITE);
71 | jumpAnimator.setRepeatMode(ValueAnimator.RESTART);
72 | jumpAnimator.addUpdateListener(this);
73 | jumpAnimator.start();
74 | }
75 |
76 | @Override
77 | public void onAnimationUpdate(ValueAnimator animation) {
78 | // No need for synchronization as this always run on main thread anyway
79 | TextView v = textView.get();
80 | if (v != null) {
81 | if (isAttachedToHierarchy(v)) {
82 | shift = (int) animation.getAnimatedValue();
83 | v.invalidate();
84 | } else {
85 | animation.setCurrentPlayTime(0);
86 | animation.start();
87 | }
88 | } else {
89 | // The textview has been destroyed and teardown() hasn't been called
90 | teardown();
91 | if (BuildConfig.DEBUG) {
92 | Log.e("JumpingBeans", "!!! Remember to call JumpingBeans.stopJumping() when appropriate !!!");
93 | }
94 | }
95 | }
96 |
97 | private boolean isAttachedToHierarchy(View v) {
98 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
99 | return v.isAttachedToWindow();
100 | } else {
101 | return v.getParent() != null; // Best-effort fallback
102 | }
103 | }
104 |
105 | /*package*/ void teardown() {
106 | if (jumpAnimator != null) {
107 | jumpAnimator.cancel();
108 | jumpAnimator.removeAllListeners();
109 | }
110 | if (textView.get() != null) {
111 | textView.clear();
112 | }
113 | }
114 |
115 | /**
116 | * A tweaked {@link android.view.animation.AccelerateDecelerateInterpolator}
117 | * that covers the full range in a fraction of its input range, and holds on
118 | * the final value on the rest of the input range. By default, this fraction
119 | * is half of the full range.
120 | *
121 | * @see net.frakbot.jumpingbeans.JumpingBeans#DEFAULT_ANIMATION_DUTY_CYCLE
122 | */
123 | private class JumpInterpolator implements TimeInterpolator {
124 |
125 | private float animRange;
126 |
127 | public JumpInterpolator(float animatedRange) {
128 | animRange = Math.abs(animatedRange);
129 | }
130 |
131 | @Override
132 | public float getInterpolation(float input) {
133 | if (input <= animRange) {
134 | return (float) (Math.cos((input / animRange + 1) * Math.PI) / 2f) + 0.5f;
135 | }
136 | return 1.0f;
137 | }
138 | }
139 | }
140 |
--------------------------------------------------------------------------------
/src/com/socks/autoload/LoadingFooter.java:
--------------------------------------------------------------------------------
1 | package com.socks.autoload;
2 |
3 | import android.content.Context;
4 | import android.view.LayoutInflater;
5 | import android.view.View;
6 | import android.widget.TextView;
7 |
8 | public class LoadingFooter {
9 |
10 | private View mLoadingFooter;
11 | private TextView mLoadingText;
12 | private State mState = State.Idle;
13 | private JumpingBeans jumpingBeans;
14 |
15 | public static enum State {
16 | Idle, TheEnd, Loading
17 | }
18 |
19 | public LoadingFooter(Context context) {
20 | mLoadingFooter = LayoutInflater.from(context).inflate(
21 | R.layout.loading_footer, null);
22 | mLoadingFooter.setOnClickListener(new View.OnClickListener() {
23 | @Override
24 | public void onClick(View v) {
25 | }
26 | });
27 | mLoadingText = (TextView) mLoadingFooter.findViewById(R.id.textView);
28 |
29 | setState(State.Idle);
30 | }
31 |
32 | public View getView() {
33 | return mLoadingFooter;
34 | }
35 |
36 | public State getState() {
37 | return mState;
38 | }
39 |
40 | public void setState(final State state, long delay) {
41 | mLoadingFooter.postDelayed(new Runnable() {
42 | @Override
43 | public void run() {
44 | setState(state);
45 | }
46 | }, delay);
47 | }
48 |
49 | public void setState(State status) {
50 | if (mState == status) {
51 | return;
52 | }
53 | mState = status;
54 |
55 | switch (status) {
56 | case Loading:
57 | mLoadingFooter.setVisibility(View.VISIBLE);
58 | mLoadingText.setText("Loading");
59 | jumpingBeans = new JumpingBeans.Builder().appendJumpingDots(
60 | mLoadingText).build();
61 | break;
62 | case TheEnd:
63 | if (jumpingBeans != null) {
64 | jumpingBeans.stopJumping();
65 | }
66 | mLoadingText.setText("No More");
67 | mLoadingFooter.setVisibility(View.VISIBLE);
68 | break;
69 | default:
70 | if (jumpingBeans != null) {
71 | jumpingBeans.stopJumping();
72 | }
73 | mLoadingFooter.setVisibility(View.GONE);
74 | break;
75 | }
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/src/com/socks/autoload/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.socks.autoload;
2 |
3 | import android.app.Activity;
4 | import android.os.Bundle;
5 | import android.os.Handler;
6 | import android.support.v4.widget.SwipeRefreshLayout;
7 | import android.view.Menu;
8 | import android.view.MenuItem;
9 | import android.view.View;
10 | import android.view.ViewGroup;
11 | import android.widget.BaseAdapter;
12 | import android.widget.TextView;
13 |
14 | import com.socks.autoload.AutoLoadListView.OnLoadNextListener;
15 | import com.socks.autoload.LoadingFooter.State;
16 | import com.socks.autoload.zlistview.ListViewAdapter;
17 |
18 | public class MainActivity extends Activity implements
19 | SwipeRefreshLayout.OnRefreshListener {
20 |
21 | // 加载更多
22 | public static final int MSG_LOAD_MORE = 0;
23 | // 刷新
24 | public static final int MSG_REFRESH = 1;
25 |
26 | private SwipeRefreshLayout swipeLayout;
27 | private AutoLoadListView listView;
28 | private Handler handler = new Handler() {
29 | public void handleMessage(android.os.Message msg) {
30 | switch (msg.what) {
31 | case MSG_LOAD_MORE:
32 |
33 | if (adapter.count < 60) {
34 | adapter.count += 20;
35 | adapter.notifyDataSetChanged();
36 | listView.setState(State.Idle);
37 | } else {
38 | listView.setState(State.TheEnd);
39 | }
40 |
41 | break;
42 | case MSG_REFRESH:
43 | swipeLayout.setRefreshing(false);
44 | adapter.count = 20;
45 | listView.smoothScrollToPosition(0);
46 | adapter.notifyDataSetChanged();
47 | listView.setState(State.Idle);
48 | break;
49 | default:
50 | break;
51 | }
52 | };
53 | };
54 | private ListViewAdapter adapter;
55 |
56 | @Override
57 | protected void onCreate(Bundle savedInstanceState) {
58 | super.onCreate(savedInstanceState);
59 | setContentView(R.layout.activity_main);
60 |
61 | swipeLayout = (SwipeRefreshLayout) this
62 | .findViewById(R.id.swipe_refresh);
63 | // 顶部刷新的样式
64 | swipeLayout.setColorSchemeResources(android.R.color.holo_red_light,
65 | android.R.color.holo_green_light,
66 | android.R.color.holo_blue_bright,
67 | android.R.color.holo_orange_light);
68 |
69 | swipeLayout.setOnRefreshListener(this);
70 |
71 | listView = (AutoLoadListView) this.findViewById(R.id.listview);
72 |
73 | adapter = new ListViewAdapter(this);
74 | listView.setAdapter(adapter);
75 | listView.setOnLoadNextListener(new OnLoadNextListener() {
76 |
77 | @Override
78 | public void onLoadNext() {
79 | handler.sendEmptyMessageDelayed(MSG_LOAD_MORE, 3000);
80 | }
81 | });
82 |
83 | }
84 |
85 | public void onRefresh() {
86 | handler.sendEmptyMessageDelayed(MSG_REFRESH, 3000);
87 | }
88 |
89 | /**
90 | * 普通的适配器
91 | */
92 | private class MyAdapter extends BaseAdapter {
93 |
94 | public int count = 20;
95 |
96 | @Override
97 | public int getCount() {
98 | return count;
99 | }
100 |
101 | @Override
102 | public Object getItem(int position) {
103 | return position;
104 | }
105 |
106 | @Override
107 | public long getItemId(int position) {
108 | return 0;
109 | }
110 |
111 | @Override
112 | public View getView(int position, View convertView, ViewGroup parent) {
113 |
114 | ViewHolder viewHolder;
115 |
116 | if (convertView == null) {
117 | convertView = getLayoutInflater().inflate(R.layout.item,
118 | parent, false);
119 | viewHolder = new ViewHolder();
120 | viewHolder.tv = (TextView) convertView.findViewById(R.id.tv);
121 | convertView.setTag(viewHolder);
122 | } else {
123 | viewHolder = (ViewHolder) convertView.getTag();
124 | }
125 |
126 | viewHolder.tv.setText("I'm " + position);
127 | return convertView;
128 | }
129 |
130 | }
131 |
132 | private static class ViewHolder {
133 | TextView tv;
134 | }
135 |
136 | @Override
137 | public boolean onOptionsItemSelected(MenuItem item) {
138 |
139 | if (item.getItemId() == R.id.action_reshresh) {
140 |
141 | swipeLayout.setRefreshing(true);
142 | handler.sendEmptyMessageDelayed(MSG_REFRESH, 3000);
143 |
144 | return true;
145 | }
146 |
147 | return super.onOptionsItemSelected(item);
148 | }
149 |
150 | @Override
151 | public boolean onCreateOptionsMenu(Menu menu) {
152 | getMenuInflater().inflate(R.menu.main, menu);
153 | return true;
154 | }
155 |
156 | }
157 |
--------------------------------------------------------------------------------
/src/com/socks/autoload/zlistview/ListViewAdapter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014, 青岛司通科技有限公司 All rights reserved.
3 | * File Name:OtherAdapter.java
4 | * Version:V1.0
5 | * Author:zhaokaiqiang
6 | * Date:2015-1-4
7 | */
8 |
9 | package com.socks.autoload.zlistview;
10 |
11 | import android.app.Activity;
12 | import android.util.Log;
13 | import android.view.View;
14 | import android.view.View.OnClickListener;
15 | import android.view.ViewGroup;
16 | import android.widget.LinearLayout;
17 | import android.widget.TextView;
18 | import android.widget.Toast;
19 |
20 | import com.socks.autoload.R;
21 | import com.socks.autoload.zlistview.adapter.BaseSwipeAdapter;
22 | import com.socks.autoload.zlistview.enums.DragEdge;
23 | import com.socks.autoload.zlistview.enums.ShowMode;
24 | import com.socks.autoload.zlistview.listener.SimpleSwipeListener;
25 |
26 | public class ListViewAdapter extends BaseSwipeAdapter {
27 |
28 | protected static final String TAG = "ListViewAdapter";
29 |
30 | public int count = 20;
31 |
32 | private Activity context;
33 |
34 | public ListViewAdapter(Activity context) {
35 | this.context = context;
36 | }
37 |
38 | @Override
39 | public int getCount() {
40 | return count;
41 | }
42 |
43 | @Override
44 | public Object getItem(int position) {
45 | return position;
46 | }
47 |
48 | @Override
49 | public long getItemId(int position) {
50 | return position;
51 | }
52 |
53 | @Override
54 | public int getSwipeLayoutResourceId(int position) {
55 | return R.id.swipe_item;
56 | }
57 |
58 | @Override
59 | public View generateView(int position, ViewGroup parent) {
60 | return context.getLayoutInflater().inflate(R.layout.item_listview,
61 | parent, false);
62 | }
63 |
64 | @Override
65 | public void fillValues(final int position, View convertView) {
66 | final ZSwipeItem swipeItem = (ZSwipeItem) convertView
67 | .findViewById(R.id.swipe_item);
68 | LinearLayout ll = (LinearLayout) convertView.findViewById(R.id.ll);
69 |
70 | TextView tv = (TextView) convertView.findViewById(R.id.tv);
71 | tv.setText(" I'm " + position);
72 |
73 | swipeItem.setShowMode(ShowMode.PullOut);
74 | swipeItem.setDragEdge(DragEdge.Right);
75 |
76 | swipeItem.addSwipeListener(new SimpleSwipeListener() {
77 | @Override
78 | public void onOpen(ZSwipeItem layout) {
79 | Log.d(TAG, "打开:" + position);
80 | }
81 |
82 | @Override
83 | public void onClose(ZSwipeItem layout) {
84 | Log.d(TAG, "关闭:" + position);
85 | }
86 |
87 | @Override
88 | public void onStartOpen(ZSwipeItem layout) {
89 | Log.d(TAG, "准备打开:" + position);
90 | }
91 |
92 | @Override
93 | public void onStartClose(ZSwipeItem layout) {
94 | Log.d(TAG, "准备关闭:" + position);
95 | }
96 |
97 | @Override
98 | public void onHandRelease(ZSwipeItem layout, float xvel, float yvel) {
99 | Log.d(TAG, "手势释放");
100 | }
101 |
102 | @Override
103 | public void onUpdate(ZSwipeItem layout, int leftOffset,
104 | int topOffset) {
105 | Log.d(TAG, "位置更新");
106 | }
107 | });
108 |
109 | ll.setOnClickListener(new OnClickListener() {
110 |
111 | @Override
112 | public void onClick(View v) {
113 | Toast.makeText(context, "删除:" + position, Toast.LENGTH_SHORT)
114 | .show();
115 | swipeItem.close();
116 | }
117 | });
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/src/com/socks/autoload/zlistview/ZSwipeItem.java:
--------------------------------------------------------------------------------
1 | package com.socks.autoload.zlistview;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.content.Context;
5 | import android.content.res.TypedArray;
6 | import android.graphics.Rect;
7 | import android.support.v4.view.ViewCompat;
8 | import android.support.v4.widget.ViewDragHelper;
9 | import android.util.AttributeSet;
10 | import android.util.Log;
11 | import android.view.GestureDetector;
12 | import android.view.MotionEvent;
13 | import android.view.View;
14 | import android.view.ViewGroup;
15 | import android.view.ViewParent;
16 | import android.widget.Adapter;
17 | import android.widget.AdapterView;
18 | import android.widget.BaseAdapter;
19 | import android.widget.FrameLayout;
20 | import android.widget.ListAdapter;
21 |
22 | import com.socks.autoload.R;
23 | import com.socks.autoload.zlistview.enums.DragEdge;
24 | import com.socks.autoload.zlistview.enums.ShowMode;
25 | import com.socks.autoload.zlistview.listener.OnSwipeLayoutListener;
26 | import com.socks.autoload.zlistview.listener.SwipeListener;
27 |
28 | import java.util.ArrayList;
29 | import java.util.List;
30 |
31 | @SuppressLint("ClickableViewAccessibility")
32 | public class ZSwipeItem extends FrameLayout {
33 |
34 | protected static final String TAG = "ZSwipeItem";
35 |
36 | private ViewDragHelper mDragHelper;
37 | private int mDragDistance = 0;
38 | private DragEdge mDragEdge;
39 | private ShowMode mShowMode;
40 |
41 | private float mHorizontalSwipeOffset;
42 | private float mVerticalSwipeOffset;
43 |
44 | private boolean mSwipeEnabled = true;
45 |
46 | private List mOnLayoutListeners;
47 | private List swipeListeners = new ArrayList();
48 |
49 | public ZSwipeItem(Context context) {
50 | this(context, null);
51 | }
52 |
53 | public ZSwipeItem(Context context, AttributeSet attrs) {
54 | this(context, attrs, 0);
55 | }
56 |
57 | public ZSwipeItem(Context context, AttributeSet attrs, int defStyle) {
58 | super(context, attrs, defStyle);
59 |
60 | mDragHelper = ViewDragHelper.create(this, mDragHelperCallback);
61 |
62 | TypedArray a = context.obtainStyledAttributes(attrs,
63 | R.styleable.ZSwipeItem);
64 | // 默认是右边缘检测
65 | int ordinal = a.getInt(R.styleable.ZSwipeItem_drag_edge,
66 | DragEdge.Right.ordinal());
67 | mDragEdge = DragEdge.values()[ordinal];
68 | // 默认模式是拉出
69 | ordinal = a.getInt(R.styleable.ZSwipeItem_show_mode,
70 | ShowMode.PullOut.ordinal());
71 | mShowMode = ShowMode.values()[ordinal];
72 |
73 | mHorizontalSwipeOffset = a.getDimension(
74 | R.styleable.ZSwipeItem_horizontalSwipeOffset, 0);
75 | mVerticalSwipeOffset = a.getDimension(
76 | R.styleable.ZSwipeItem_verticalSwipeOffset, 0);
77 |
78 | a.recycle();
79 | }
80 |
81 | /**
82 | * 进行拖拽的主要类
83 | */
84 | private ViewDragHelper.Callback mDragHelperCallback = new ViewDragHelper.Callback() {
85 |
86 | /**
87 | * 计算被横向拖动view的left
88 | */
89 | @Override
90 | public int clampViewPositionHorizontal(View child, int left, int dx) {
91 | if (child == getSurfaceView()) {
92 | switch (mDragEdge) {
93 | case Top:
94 | case Bottom:
95 | return getPaddingLeft();
96 | case Left:
97 | if (left < getPaddingLeft())
98 | return getPaddingLeft();
99 | if (left > getPaddingLeft() + mDragDistance)
100 | return getPaddingLeft() + mDragDistance;
101 | break;
102 | case Right:
103 | if (left > getPaddingLeft())
104 | return getPaddingLeft();
105 | if (left < getPaddingLeft() - mDragDistance)
106 | return getPaddingLeft() - mDragDistance;
107 | break;
108 | }
109 | } else if (child == getBottomView()) {
110 |
111 | switch (mDragEdge) {
112 | case Top:
113 | case Bottom:
114 | return getPaddingLeft();
115 | case Left:
116 | if (mShowMode == ShowMode.PullOut) {
117 | if (left > getPaddingLeft())
118 | return getPaddingLeft();
119 | }
120 | break;
121 | case Right:
122 | if (mShowMode == ShowMode.PullOut) {
123 | if (left < getMeasuredWidth() - mDragDistance) {
124 | return getMeasuredWidth() - mDragDistance;
125 | }
126 | }
127 | break;
128 | }
129 | }
130 | return left;
131 | }
132 |
133 | /**
134 | * 计算被纵向拖动的view的top
135 | */
136 | @Override
137 | public int clampViewPositionVertical(View child, int top, int dy) {
138 | if (child == getSurfaceView()) {
139 | switch (mDragEdge) {
140 | case Left:
141 | case Right:
142 | return getPaddingTop();
143 | case Top:
144 | if (top < getPaddingTop())
145 | return getPaddingTop();
146 | if (top > getPaddingTop() + mDragDistance)
147 | return getPaddingTop() + mDragDistance;
148 | break;
149 | case Bottom:
150 | if (top < getPaddingTop() - mDragDistance) {
151 | return getPaddingTop() - mDragDistance;
152 | }
153 | if (top > getPaddingTop()) {
154 | return getPaddingTop();
155 | }
156 | }
157 | } else {
158 | switch (mDragEdge) {
159 | case Left:
160 | case Right:
161 | return getPaddingTop();
162 | case Top:
163 | if (mShowMode == ShowMode.PullOut) {
164 | if (top > getPaddingTop())
165 | return getPaddingTop();
166 | } else {
167 | if (getSurfaceView().getTop() + dy < getPaddingTop())
168 | return getPaddingTop();
169 | if (getSurfaceView().getTop() + dy > getPaddingTop()
170 | + mDragDistance)
171 | return getPaddingTop() + mDragDistance;
172 | }
173 | break;
174 | case Bottom:
175 | if (mShowMode == ShowMode.PullOut) {
176 | if (top < getMeasuredHeight() - mDragDistance)
177 | return getMeasuredHeight() - mDragDistance;
178 | } else {
179 | if (getSurfaceView().getTop() + dy >= getPaddingTop())
180 | return getPaddingTop();
181 | if (getSurfaceView().getTop() + dy <= getPaddingTop()
182 | - mDragDistance)
183 | return getPaddingTop() - mDragDistance;
184 | }
185 | }
186 | }
187 | return top;
188 | }
189 |
190 | /**
191 | * 确定要进行拖动的view
192 | */
193 | @Override
194 | public boolean tryCaptureView(View child, int pointerId) {
195 | return child == getSurfaceView() || child == getBottomView();
196 | }
197 |
198 | /**
199 | * 确定横向拖动边界
200 | */
201 | @Override
202 | public int getViewHorizontalDragRange(View child) {
203 | return mDragDistance;
204 | }
205 |
206 | /**
207 | * 确定纵向拖动边界
208 | */
209 | @Override
210 | public int getViewVerticalDragRange(View child) {
211 | return mDragDistance;
212 | }
213 |
214 | /**
215 | * 当子控件被释放的时候调用,可以获取加速度的数据,来判断用户意图
216 | */
217 | @Override
218 | public void onViewReleased(View releasedChild, float xvel, float yvel) {
219 | super.onViewReleased(releasedChild, xvel, yvel);
220 |
221 | for (SwipeListener l : swipeListeners) {
222 | l.onHandRelease(ZSwipeItem.this, xvel, yvel);
223 | }
224 |
225 | if (releasedChild == getSurfaceView()) {
226 | processSurfaceRelease(xvel, yvel);
227 | } else if (releasedChild == getBottomView()) {
228 | if (getShowMode() == ShowMode.PullOut) {
229 | processBottomPullOutRelease(xvel, yvel);
230 | } else if (getShowMode() == ShowMode.LayDown) {
231 | processBottomLayDownMode(xvel, yvel);
232 | }
233 | }
234 |
235 | invalidate();
236 | }
237 |
238 | /**
239 | * 当view的位置发生变化的时候调用,可以设置view的位置跟随手指移动
240 | */
241 | @Override
242 | public void onViewPositionChanged(View changedView, int left, int top,
243 | int dx, int dy) {
244 |
245 | int evLeft = getSurfaceView().getLeft();
246 | int evTop = getSurfaceView().getTop();
247 |
248 | if (changedView == getSurfaceView()) {
249 |
250 | if (mShowMode == ShowMode.PullOut) {
251 | if (mDragEdge == DragEdge.Left
252 | || mDragEdge == DragEdge.Right) {
253 | getBottomView().offsetLeftAndRight(dx);
254 | } else {
255 | getBottomView().offsetTopAndBottom(dy);
256 | }
257 | }
258 |
259 | } else if (changedView == getBottomView()) {
260 |
261 | if (mShowMode == ShowMode.PullOut) {
262 | getSurfaceView().offsetLeftAndRight(dx);
263 | getSurfaceView().offsetTopAndBottom(dy);
264 | } else {
265 | Rect rect = computeBottomLayDown(mDragEdge);
266 | getBottomView().layout(rect.left, rect.top, rect.right,
267 | rect.bottom);
268 |
269 | int newLeft = getSurfaceView().getLeft() + dx;
270 | int newTop = getSurfaceView().getTop() + dy;
271 |
272 | if (mDragEdge == DragEdge.Left
273 | && newLeft < getPaddingLeft())
274 | newLeft = getPaddingLeft();
275 | else if (mDragEdge == DragEdge.Right
276 | && newLeft > getPaddingLeft())
277 | newLeft = getPaddingLeft();
278 | else if (mDragEdge == DragEdge.Top
279 | && newTop < getPaddingTop())
280 | newTop = getPaddingTop();
281 | else if (mDragEdge == DragEdge.Bottom
282 | && newTop > getPaddingTop())
283 | newTop = getPaddingTop();
284 |
285 | getSurfaceView().layout(newLeft, newTop,
286 | newLeft + getMeasuredWidth(),
287 | newTop + getMeasuredHeight());
288 | }
289 | }
290 |
291 | // 及时派发滑动事件
292 | dispatchSwipeEvent(evLeft, evTop, dx, dy);
293 |
294 | invalidate();
295 | }
296 | };
297 |
298 | /**
299 | * swipe事件分发器
300 | *
301 | * @param surfaceLeft
302 | * @param surfaceTop
303 | * @param dx
304 | * @param dy
305 | */
306 | protected void dispatchSwipeEvent(int surfaceLeft, int surfaceTop, int dx,
307 | int dy) {
308 | DragEdge edge = getDragEdge();
309 | boolean open = true;
310 | if (edge == DragEdge.Left) {
311 | if (dx < 0)
312 | open = false;
313 | } else if (edge == DragEdge.Right) {
314 | if (dx > 0)
315 | open = false;
316 | } else if (edge == DragEdge.Top) {
317 | if (dy < 0)
318 | open = false;
319 | } else if (edge == DragEdge.Bottom) {
320 | if (dy > 0)
321 | open = false;
322 | }
323 |
324 | dispatchSwipeEvent(surfaceLeft, surfaceTop, open);
325 | }
326 |
327 | private int mEventCounter = 0;
328 |
329 | /**
330 | * swipe事件分发器
331 | *
332 | * @param surfaceLeft
333 | * @param surfaceTop
334 | * @param open
335 | */
336 | protected void dispatchSwipeEvent(int surfaceLeft, int surfaceTop,
337 | boolean open) {
338 |
339 | safeBottomView();
340 | Status status = getOpenStatus();
341 |
342 | if (!swipeListeners.isEmpty()) {
343 |
344 | Log.d(TAG, "swipeListeners=" + swipeListeners.size());
345 |
346 | mEventCounter++;
347 |
348 | if (mEventCounter == 1) {
349 | if (open) {
350 | swipeListeners.get(0).onStartOpen(ZSwipeItem.this);
351 | swipeListeners.get(swipeListeners.size() - 1).onStartOpen(
352 | ZSwipeItem.this);
353 | } else {
354 | swipeListeners.get(0).onStartClose(ZSwipeItem.this);
355 | swipeListeners.get(swipeListeners.size() - 1).onStartClose(
356 | ZSwipeItem.this);
357 | }
358 | }
359 |
360 | for (SwipeListener l : swipeListeners) {
361 | l.onUpdate(ZSwipeItem.this, surfaceLeft - getPaddingLeft(),
362 | surfaceTop - getPaddingTop());
363 | }
364 |
365 | if (status == Status.Close) {
366 | swipeListeners.get(0).onClose(ZSwipeItem.this);
367 | swipeListeners.get(swipeListeners.size() - 1).onClose(
368 | ZSwipeItem.this);
369 | mEventCounter = 0;
370 | } else if (status == Status.Open) {
371 | getBottomView().setEnabled(true);
372 | swipeListeners.get(0).onOpen(ZSwipeItem.this);
373 | swipeListeners.get(swipeListeners.size() - 1).onOpen(
374 | ZSwipeItem.this);
375 | mEventCounter = 0;
376 | }
377 | }
378 | }
379 |
380 | /**
381 | * 防止底布局获取到任何的触摸事件,特别是在LayDown模式
382 | */
383 | private void safeBottomView() {
384 | Status status = getOpenStatus();
385 | ViewGroup bottom = getBottomView();
386 |
387 | if (status == Status.Close) {
388 | if (bottom.getVisibility() != INVISIBLE)
389 | bottom.setVisibility(INVISIBLE);
390 | } else {
391 | if (bottom.getVisibility() != VISIBLE)
392 | bottom.setVisibility(VISIBLE);
393 | }
394 | }
395 |
396 | @Override
397 | public void computeScroll() {
398 | super.computeScroll();
399 | // 让滚动一直进行下去
400 | if (mDragHelper.continueSettling(true)) {
401 | ViewCompat.postInvalidateOnAnimation(this);
402 | }
403 | }
404 |
405 | /**
406 | * 强制布局中必须嵌套两个ViewGroup布局,在新item出现的时候就会调用
407 | */
408 | @SuppressLint("WrongCall")
409 | @Override
410 | protected void onLayout(boolean changed, int l, int t, int r, int b) {
411 | int childCount = getChildCount();
412 | if (childCount != 2) {
413 | throw new IllegalStateException("You need 2 views in SwipeLayout");
414 | }
415 | if (!(getChildAt(0) instanceof ViewGroup)
416 | || !(getChildAt(1) instanceof ViewGroup)) {
417 | throw new IllegalArgumentException(
418 | "The 2 children in SwipeLayout must be an instance of ViewGroup");
419 | }
420 |
421 | if (mShowMode == ShowMode.PullOut) {
422 | layoutPullOut();
423 | } else if (mShowMode == ShowMode.LayDown) {
424 | layoutLayDown();
425 | }
426 |
427 | safeBottomView();
428 |
429 | if (mOnLayoutListeners != null)
430 | for (int i = 0; i < mOnLayoutListeners.size(); i++) {
431 | mOnLayoutListeners.get(i).onLayout(this);
432 | }
433 |
434 | }
435 |
436 | private void layoutPullOut() {
437 | Rect rect = computeSurfaceLayoutArea(false);
438 | getSurfaceView().layout(rect.left, rect.top, rect.right, rect.bottom);
439 | rect = computeBottomLayoutAreaViaSurface(ShowMode.PullOut, rect);
440 | getBottomView().layout(rect.left, rect.top, rect.right, rect.bottom);
441 | bringChildToFront(getSurfaceView());
442 | }
443 |
444 | private void layoutLayDown() {
445 | Rect rect = computeSurfaceLayoutArea(false);
446 | getSurfaceView().layout(rect.left, rect.top, rect.right, rect.bottom);
447 | rect = computeBottomLayoutAreaViaSurface(ShowMode.LayDown, rect);
448 | getBottomView().layout(rect.left, rect.top, rect.right, rect.bottom);
449 | bringChildToFront(getSurfaceView());
450 | }
451 |
452 | @Override
453 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
454 | super.onMeasure(widthMeasureSpec, heightMeasureSpec);
455 | // 初始化移动距离
456 | if (mDragEdge == DragEdge.Left || mDragEdge == DragEdge.Right)
457 | mDragDistance = getBottomView().getMeasuredWidth()
458 | - dp2px(mHorizontalSwipeOffset);
459 | else {
460 | mDragDistance = getBottomView().getMeasuredHeight()
461 | - dp2px(mVerticalSwipeOffset);
462 | }
463 | }
464 |
465 | private boolean mTouchConsumedByChild = false;
466 |
467 | @Override
468 | public boolean onInterceptTouchEvent(MotionEvent ev) {
469 |
470 | if (!isEnabled() || !isEnabledInAdapterView()) {
471 | return true;
472 | }
473 |
474 | if (!isSwipeEnabled()) {
475 | return false;
476 | }
477 |
478 | int action = ev.getActionMasked();
479 | switch (action) {
480 | case MotionEvent.ACTION_DOWN:
481 | Status status = getOpenStatus();
482 | if (status == Status.Close) {
483 | mTouchConsumedByChild = childNeedHandleTouchEvent(
484 | getSurfaceView(), ev) != null;
485 | } else if (status == Status.Open) {
486 | mTouchConsumedByChild = childNeedHandleTouchEvent(
487 | getBottomView(), ev) != null;
488 | }
489 | break;
490 | case MotionEvent.ACTION_UP:
491 | case MotionEvent.ACTION_CANCEL:
492 | mTouchConsumedByChild = false;
493 | }
494 |
495 | if (mTouchConsumedByChild)
496 | return false;
497 | return mDragHelper.shouldInterceptTouchEvent(ev);
498 | }
499 |
500 | /**
501 | * ViewGroup的子View是否需要处理这个事件
502 | *
503 | * @param v
504 | * @param event
505 | * @return
506 | */
507 | private View childNeedHandleTouchEvent(ViewGroup v, MotionEvent event) {
508 | if (v == null)
509 | return null;
510 | if (v.onTouchEvent(event))
511 | return v;
512 |
513 | int childCount = v.getChildCount();
514 | for (int i = childCount - 1; i >= 0; i--) {
515 | View child = v.getChildAt(i);
516 | if (child instanceof ViewGroup) {
517 | View grandChild = childNeedHandleTouchEvent((ViewGroup) child,
518 | event);
519 | if (grandChild != null)
520 | return grandChild;
521 | } else {
522 | if (childNeedHandleTouchEvent(v.getChildAt(i), event))
523 | return v.getChildAt(i);
524 | }
525 | }
526 | return null;
527 | }
528 |
529 | /**
530 | * 判断View是否要去处理触摸事件
531 | *
532 | * @param v
533 | * @param event
534 | * @return
535 | */
536 | private boolean childNeedHandleTouchEvent(View v, MotionEvent event) {
537 | if (v == null)
538 | return false;
539 |
540 | int[] loc = new int[2];
541 | v.getLocationOnScreen(loc);
542 | int left = loc[0];
543 | int top = loc[1];
544 |
545 | if (event.getRawX() > left && event.getRawX() < left + v.getWidth()
546 | && event.getRawY() > top
547 | && event.getRawY() < top + v.getHeight()) {
548 | return v.onTouchEvent(event);
549 | }
550 |
551 | return false;
552 | }
553 |
554 | private float sX = -1, sY = -1;
555 |
556 | @Override
557 | public boolean onTouchEvent(MotionEvent event) {
558 | if (!isEnabledInAdapterView() || !isEnabled())
559 | return true;
560 |
561 | if (!isSwipeEnabled())
562 | return super.onTouchEvent(event);
563 |
564 | int action = event.getActionMasked();
565 | ViewParent parent = getParent();
566 |
567 | gestureDetector.onTouchEvent(event);
568 |
569 | Status status = getOpenStatus();
570 | ViewGroup touching = null;
571 | if (status == Status.Close) {
572 | touching = getSurfaceView();
573 | } else if (status == Status.Open) {
574 | touching = getBottomView();
575 | }
576 |
577 | switch (action) {
578 | case MotionEvent.ACTION_DOWN:
579 | mDragHelper.processTouchEvent(event);
580 | parent.requestDisallowInterceptTouchEvent(true);
581 |
582 | sX = event.getRawX();
583 | sY = event.getRawY();
584 |
585 | if (touching != null)
586 | touching.setPressed(true);
587 |
588 | return true;
589 | case MotionEvent.ACTION_MOVE: {
590 | if (sX == -1 || sY == -1) {
591 | // Trick:
592 | // When in nested mode, we need to send a constructed
593 | // ACTION_DOWN MotionEvent to mDragHelper, to help
594 | // it initialize itself.
595 | event.setAction(MotionEvent.ACTION_DOWN);
596 | mDragHelper.processTouchEvent(event);
597 | parent.requestDisallowInterceptTouchEvent(true);
598 | sX = event.getRawX();
599 | sY = event.getRawY();
600 | return true;
601 | }
602 |
603 | float distanceX = event.getRawX() - sX;
604 | float distanceY = event.getRawY() - sY;
605 | float angle = Math.abs(distanceY / distanceX);
606 | angle = (float) Math.toDegrees(Math.atan(angle));
607 |
608 | boolean doNothing = false;
609 | // 根据触摸角度,判断是否执行用户操作
610 | if (mDragEdge == DragEdge.Right) {
611 | boolean suitable = (status == Status.Open && distanceX > 0)
612 | || (status == Status.Close && distanceX < 0);
613 | suitable = suitable || (status == Status.Middle);
614 |
615 | if (angle > 30 || !suitable) {
616 | doNothing = true;
617 | }
618 | }
619 |
620 | if (mDragEdge == DragEdge.Left) {
621 | boolean suitable = (status == Status.Open && distanceX < 0)
622 | || (status == Status.Close && distanceX > 0);
623 | suitable = suitable || status == Status.Middle;
624 |
625 | if (angle > 30 || !suitable) {
626 | doNothing = true;
627 | }
628 | }
629 |
630 | if (mDragEdge == DragEdge.Top) {
631 | boolean suitable = (status == Status.Open && distanceY < 0)
632 | || (status == Status.Close && distanceY > 0);
633 | suitable = suitable || status == Status.Middle;
634 |
635 | if (angle < 60 || !suitable) {
636 | doNothing = true;
637 | }
638 | }
639 |
640 | if (mDragEdge == DragEdge.Bottom) {
641 | boolean suitable = (status == Status.Open && distanceY > 0)
642 | || (status == Status.Close && distanceY < 0);
643 | suitable = suitable || status == Status.Middle;
644 |
645 | if (angle < 60 || !suitable) {
646 | doNothing = true;
647 | }
648 | }
649 |
650 | if (doNothing) {
651 | // 拦截触摸事件
652 | parent.requestDisallowInterceptTouchEvent(false);
653 | return false;
654 | } else {
655 | if (touching != null) {
656 | touching.setPressed(false);
657 | }
658 | parent.requestDisallowInterceptTouchEvent(true);
659 | mDragHelper.processTouchEvent(event);
660 | }
661 | break;
662 | }
663 | case MotionEvent.ACTION_UP:
664 | case MotionEvent.ACTION_CANCEL: {
665 | sX = -1;
666 | sY = -1;
667 | if (touching != null) {
668 | touching.setPressed(false);
669 | }
670 | }
671 | default:
672 | parent.requestDisallowInterceptTouchEvent(true);
673 | mDragHelper.processTouchEvent(event);
674 | }
675 |
676 | return true;
677 | }
678 |
679 | /**
680 | * if working in {@link android.widget.AdapterView}, we should response
681 | * {@link android.widget.Adapter} isEnable(int position).
682 | *
683 | * @return true when item is enabled, else disabled.
684 | */
685 | private boolean isEnabledInAdapterView() {
686 | @SuppressWarnings("rawtypes")
687 | AdapterView adapterView = getAdapterView();
688 | boolean enable = true;
689 | if (adapterView != null) {
690 | Adapter adapter = adapterView.getAdapter();
691 | if (adapter != null) {
692 | int p = adapterView.getPositionForView(ZSwipeItem.this);
693 | if (adapter instanceof BaseAdapter) {
694 | enable = ((BaseAdapter) adapter).isEnabled(p);
695 | } else if (adapter instanceof ListAdapter) {
696 | enable = ((ListAdapter) adapter).isEnabled(p);
697 | }
698 | }
699 | }
700 | return enable;
701 | }
702 |
703 | public void setSwipeEnabled(boolean enabled) {
704 | mSwipeEnabled = enabled;
705 | }
706 |
707 | public boolean isSwipeEnabled() {
708 | return mSwipeEnabled;
709 | }
710 |
711 | @SuppressWarnings("rawtypes")
712 | private AdapterView getAdapterView() {
713 | ViewParent t = getParent();
714 | while (t != null) {
715 | if (t instanceof AdapterView) {
716 | return (AdapterView) t;
717 | }
718 | t = t.getParent();
719 | }
720 | return null;
721 | }
722 |
723 | private void performAdapterViewItemClick(MotionEvent e) {
724 | ViewParent t = getParent();
725 |
726 | Log.d(TAG, "performAdapterViewItemClick()");
727 |
728 | while (t != null) {
729 | if (t instanceof AdapterView) {
730 | @SuppressWarnings("rawtypes")
731 | AdapterView view = (AdapterView) t;
732 | int p = view.getPositionForView(ZSwipeItem.this);
733 | if (p != AdapterView.INVALID_POSITION
734 | && view.performItemClick(
735 | view.getChildAt(p
736 | - view.getFirstVisiblePosition()), p,
737 | view.getAdapter().getItemId(p)))
738 | return;
739 | } else {
740 | if (t instanceof View && ((View) t).performClick())
741 | return;
742 | }
743 |
744 | t = t.getParent();
745 | }
746 | }
747 |
748 | private GestureDetector gestureDetector = new GestureDetector(getContext(),
749 | new SwipeDetector());
750 |
751 | /**
752 | * 手势监听器,通过调用performItemClick、performItemLongClick,来解决item的点击问题,
753 | *
754 | * @author zhaokaiqiang
755 | * @class: com.socks.zlistview.SwipeDetector
756 | * @date 2015-1-7 下午3:44:09
757 | */
758 | private class SwipeDetector extends GestureDetector.SimpleOnGestureListener {
759 | @Override
760 | public boolean onDown(MotionEvent e) {
761 | return true;
762 | }
763 |
764 | @Override
765 | public boolean onSingleTapUp(MotionEvent e) {
766 | // 当用户单击之后,手指抬起的时候调用,如果没有双击监听器,就直接调用
767 | performAdapterViewItemClick(e);
768 | return true;
769 | }
770 |
771 | @Override
772 | public boolean onSingleTapConfirmed(MotionEvent e) {
773 | // 这个方法只有在确认用户不会发生双击事件的时候调用
774 | return false;
775 | }
776 |
777 | @Override
778 | public void onLongPress(MotionEvent e) {
779 | // 长按事件
780 | performLongClick();
781 | }
782 |
783 | @Override
784 | public boolean onDoubleTap(MotionEvent e) {
785 | return false;
786 | }
787 | }
788 |
789 | public void setDragEdge(DragEdge dragEdge) {
790 | mDragEdge = dragEdge;
791 | requestLayout();
792 | }
793 |
794 | public void setShowMode(ShowMode mode) {
795 | mShowMode = mode;
796 | requestLayout();
797 | }
798 |
799 | public DragEdge getDragEdge() {
800 | return mDragEdge;
801 | }
802 |
803 | public int getDragDistance() {
804 | return mDragDistance;
805 | }
806 |
807 | public ShowMode getShowMode() {
808 | return mShowMode;
809 | }
810 |
811 | public ViewGroup getSurfaceView() {
812 | return (ViewGroup) getChildAt(1);
813 | }
814 |
815 | public ViewGroup getBottomView() {
816 | return (ViewGroup) getChildAt(0);
817 | }
818 |
819 | public enum Status {
820 | Middle, Open, Close
821 | }
822 |
823 | /**
824 | * 获取当前的开启状态
825 | *
826 | * @return
827 | */
828 | public Status getOpenStatus() {
829 | int surfaceLeft = getSurfaceView().getLeft();
830 | int surfaceTop = getSurfaceView().getTop();
831 | if (surfaceLeft == getPaddingLeft() && surfaceTop == getPaddingTop())
832 | return Status.Close;
833 |
834 | if (surfaceLeft == (getPaddingLeft() - mDragDistance)
835 | || surfaceLeft == (getPaddingLeft() + mDragDistance)
836 | || surfaceTop == (getPaddingTop() - mDragDistance)
837 | || surfaceTop == (getPaddingTop() + mDragDistance))
838 | return Status.Open;
839 |
840 | return Status.Middle;
841 | }
842 |
843 | /**
844 | * 执行前布局的释放过程
845 | *
846 | * @param xvel
847 | * @param yvel
848 | */
849 | private void processSurfaceRelease(float xvel, float yvel) {
850 | if (xvel == 0 && getOpenStatus() == Status.Middle)
851 | close();
852 |
853 | if (mDragEdge == DragEdge.Left || mDragEdge == DragEdge.Right) {
854 | if (xvel > 0) {
855 | if (mDragEdge == DragEdge.Left)
856 | open();
857 | else
858 | close();
859 | }
860 | if (xvel < 0) {
861 | if (mDragEdge == DragEdge.Left)
862 | close();
863 | else
864 | open();
865 | }
866 | } else {
867 | if (yvel > 0) {
868 | if (mDragEdge == DragEdge.Top)
869 | open();
870 | else
871 | close();
872 | }
873 | if (yvel < 0) {
874 | if (mDragEdge == DragEdge.Top)
875 | close();
876 | else
877 | open();
878 | }
879 | }
880 | }
881 |
882 | /**
883 | * 执行PullOut模式下,底布局的释放过程
884 | *
885 | * @param xvel
886 | * @param yvel
887 | */
888 | private void processBottomPullOutRelease(float xvel, float yvel) {
889 |
890 | if (xvel == 0 && getOpenStatus() == Status.Middle)
891 | close();
892 |
893 | if (mDragEdge == DragEdge.Left || mDragEdge == DragEdge.Right) {
894 | if (xvel > 0) {
895 | if (mDragEdge == DragEdge.Left)
896 | open();
897 | else
898 | close();
899 | }
900 | if (xvel < 0) {
901 | if (mDragEdge == DragEdge.Left)
902 | close();
903 | else
904 | open();
905 | }
906 | } else {
907 | if (yvel > 0) {
908 | if (mDragEdge == DragEdge.Top)
909 | open();
910 | else
911 | close();
912 | }
913 |
914 | if (yvel < 0) {
915 | if (mDragEdge == DragEdge.Top)
916 | close();
917 | else
918 | open();
919 | }
920 | }
921 | }
922 |
923 | /**
924 | * 执行LayDown模式下,底布局的释放过程
925 | *
926 | * @param xvel
927 | * @param yvel
928 | */
929 | private void processBottomLayDownMode(float xvel, float yvel) {
930 |
931 | if (xvel == 0 && getOpenStatus() == Status.Middle)
932 | close();
933 |
934 | int l = getPaddingLeft(), t = getPaddingTop();
935 |
936 | if (xvel < 0 && mDragEdge == DragEdge.Right)
937 | l -= mDragDistance;
938 | if (xvel > 0 && mDragEdge == DragEdge.Left)
939 | l += mDragDistance;
940 |
941 | if (yvel > 0 && mDragEdge == DragEdge.Top)
942 | t += mDragDistance;
943 | if (yvel < 0 && mDragEdge == DragEdge.Bottom)
944 | t -= mDragDistance;
945 |
946 | mDragHelper.smoothSlideViewTo(getSurfaceView(), l, t);
947 | invalidate();
948 | }
949 |
950 | public void open() {
951 | open(true, true);
952 | }
953 |
954 | public void open(boolean smooth) {
955 | open(smooth, true);
956 | }
957 |
958 | public void open(boolean smooth, boolean notify) {
959 | ViewGroup surface = getSurfaceView(), bottom = getBottomView();
960 | int dx, dy;
961 | Rect rect = computeSurfaceLayoutArea(true);
962 | if (smooth) {
963 | mDragHelper
964 | .smoothSlideViewTo(getSurfaceView(), rect.left, rect.top);
965 | } else {
966 | dx = rect.left - surface.getLeft();
967 | dy = rect.top - surface.getTop();
968 | surface.layout(rect.left, rect.top, rect.right, rect.bottom);
969 | if (getShowMode() == ShowMode.PullOut) {
970 | Rect bRect = computeBottomLayoutAreaViaSurface(
971 | ShowMode.PullOut, rect);
972 | bottom.layout(bRect.left, bRect.top, bRect.right, bRect.bottom);
973 | }
974 | if (notify) {
975 | dispatchSwipeEvent(rect.left, rect.top, dx, dy);
976 | } else {
977 | safeBottomView();
978 | }
979 | }
980 | invalidate();
981 | }
982 |
983 | public void close() {
984 | close(true, true);
985 | }
986 |
987 | public void close(boolean smooth) {
988 | close(smooth, true);
989 | }
990 |
991 | public void close(boolean smooth, boolean notify) {
992 | ViewGroup surface = getSurfaceView();
993 | int dx, dy;
994 | if (smooth)
995 | mDragHelper.smoothSlideViewTo(getSurfaceView(), getPaddingLeft(),
996 | getPaddingTop());
997 | else {
998 | Rect rect = computeSurfaceLayoutArea(false);
999 | dx = rect.left - surface.getLeft();
1000 | dy = rect.top - surface.getTop();
1001 | surface.layout(rect.left, rect.top, rect.right, rect.bottom);
1002 | if (notify) {
1003 | dispatchSwipeEvent(rect.left, rect.top, dx, dy);
1004 | } else {
1005 | safeBottomView();
1006 | }
1007 | }
1008 | invalidate();
1009 | }
1010 |
1011 | public void toggle() {
1012 | toggle(true);
1013 | }
1014 |
1015 | public void toggle(boolean smooth) {
1016 | if (getOpenStatus() == Status.Open)
1017 | close(smooth);
1018 | else if (getOpenStatus() == Status.Close)
1019 | open(smooth);
1020 | }
1021 |
1022 | private Rect computeSurfaceLayoutArea(boolean open) {
1023 | int l = getPaddingLeft(), t = getPaddingTop();
1024 | if (open) {
1025 | if (mDragEdge == DragEdge.Left)
1026 | l = getPaddingLeft() + mDragDistance;
1027 | else if (mDragEdge == DragEdge.Right)
1028 | l = getPaddingLeft() - mDragDistance;
1029 | else if (mDragEdge == DragEdge.Top)
1030 | t = getPaddingTop() + mDragDistance;
1031 | else
1032 | t = getPaddingTop() - mDragDistance;
1033 | }
1034 | return new Rect(l, t, l + getMeasuredWidth(), t + getMeasuredHeight());
1035 | }
1036 |
1037 | private Rect computeBottomLayoutAreaViaSurface(ShowMode mode,
1038 | Rect surfaceArea) {
1039 | Rect rect = surfaceArea;
1040 |
1041 | int bl = rect.left, bt = rect.top, br = rect.right, bb = rect.bottom;
1042 | if (mode == ShowMode.PullOut) {
1043 | if (mDragEdge == DragEdge.Left)
1044 | bl = rect.left - mDragDistance;
1045 | else if (mDragEdge == DragEdge.Right)
1046 | bl = rect.right;
1047 | else if (mDragEdge == DragEdge.Top)
1048 | bt = rect.top - mDragDistance;
1049 | else
1050 | bt = rect.bottom;
1051 |
1052 | if (mDragEdge == DragEdge.Left || mDragEdge == DragEdge.Right) {
1053 | bb = rect.bottom;
1054 | br = bl + getBottomView().getMeasuredWidth();
1055 | } else {
1056 | bb = bt + getBottomView().getMeasuredHeight();
1057 | br = rect.right;
1058 | }
1059 | } else if (mode == ShowMode.LayDown) {
1060 | if (mDragEdge == DragEdge.Left)
1061 | br = bl + mDragDistance;
1062 | else if (mDragEdge == DragEdge.Right)
1063 | bl = br - mDragDistance;
1064 | else if (mDragEdge == DragEdge.Top)
1065 | bb = bt + mDragDistance;
1066 | else
1067 | bt = bb - mDragDistance;
1068 |
1069 | }
1070 | return new Rect(bl, bt, br, bb);
1071 |
1072 | }
1073 |
1074 | private Rect computeBottomLayDown(DragEdge dragEdge) {
1075 | int bl = getPaddingLeft(), bt = getPaddingTop();
1076 | int br, bb;
1077 | if (dragEdge == DragEdge.Right) {
1078 | bl = getMeasuredWidth() - mDragDistance;
1079 | } else if (dragEdge == DragEdge.Bottom) {
1080 | bt = getMeasuredHeight() - mDragDistance;
1081 | }
1082 | if (dragEdge == DragEdge.Left || dragEdge == DragEdge.Right) {
1083 | br = bl + mDragDistance;
1084 | bb = bt + getMeasuredHeight();
1085 | } else {
1086 | br = bl + getMeasuredWidth();
1087 | bb = bt + mDragDistance;
1088 | }
1089 | return new Rect(bl, bt, br, bb);
1090 | }
1091 |
1092 | public void addSwipeListener(SwipeListener l) {
1093 |
1094 | if (swipeListeners.size() == 2) {
1095 | swipeListeners.remove(1);
1096 | }
1097 |
1098 | swipeListeners.add(l);
1099 | }
1100 |
1101 | public void removeSwipeListener(SwipeListener l) {
1102 | swipeListeners.remove(l);
1103 | }
1104 |
1105 | public void addOnLayoutListener(OnSwipeLayoutListener l) {
1106 | if (mOnLayoutListeners == null)
1107 | mOnLayoutListeners = new ArrayList();
1108 | mOnLayoutListeners.add(l);
1109 | }
1110 |
1111 | public void removeOnLayoutListener(OnSwipeLayoutListener l) {
1112 | if (mOnLayoutListeners != null)
1113 | mOnLayoutListeners.remove(l);
1114 | }
1115 |
1116 | private int dp2px(float dp) {
1117 | return (int) (dp
1118 | * getContext().getResources().getDisplayMetrics().density + 0.5f);
1119 | }
1120 | }
1121 |
--------------------------------------------------------------------------------
/src/com/socks/autoload/zlistview/adapter/BaseSwipeAdapter.java:
--------------------------------------------------------------------------------
1 | package com.socks.autoload.zlistview.adapter;
2 |
3 | import android.util.Log;
4 | import android.view.View;
5 | import android.view.ViewGroup;
6 | import android.widget.BaseAdapter;
7 |
8 | import com.socks.autoload.zlistview.ZSwipeItem;
9 | import com.socks.autoload.zlistview.enums.Mode;
10 | import com.socks.autoload.zlistview.listener.OnSwipeLayoutListener;
11 | import com.socks.autoload.zlistview.listener.SimpleSwipeListener;
12 |
13 | import java.util.ArrayList;
14 | import java.util.Arrays;
15 | import java.util.HashSet;
16 | import java.util.List;
17 | import java.util.Set;
18 |
19 | /**
20 | * 如果要使用ZSwipeItem,请继承这个Adapter
21 | *
22 | * @author zhaokaiqiang
23 | * @class: com.socks.zlistview.adapter.BaseSwipeAdapter
24 | * @date 2015-1-8 上午10:05:04
25 | */
26 | public abstract class BaseSwipeAdapter extends BaseAdapter {
27 |
28 | public static final String TAG = "BaseSwipeAdapter";
29 |
30 | public final int INVALID_POSITION = -1;
31 | /**
32 | * 显示模式,默认单开
33 | */
34 | private Mode mode = Mode.Single;
35 | /**
36 | * 当前打开的item的position
37 | */
38 | protected int openPosition = INVALID_POSITION;
39 | /**
40 | * 当前打开的所有item的position
41 | */
42 | protected Set openPositions = new HashSet();
43 | /**
44 | * 当前打开的所有ZSwipeItem对象
45 | */
46 | protected Set mShownLayouts = new HashSet();
47 |
48 | public abstract int getSwipeLayoutResourceId(int position);
49 |
50 | public abstract View generateView(int position, ViewGroup parent);
51 |
52 | public abstract void fillValues(int position, View convertView);
53 |
54 | @Override
55 | public final View getView(int position, View convertView, ViewGroup parent) {
56 |
57 | if (convertView == null) {
58 | convertView = generateView(position, parent);
59 | initialize(convertView, position);
60 | } else {
61 | updateConvertView(convertView, position);
62 | }
63 | fillValues(position, convertView);
64 | return convertView;
65 |
66 | }
67 |
68 | /**
69 | * 初始化item布局调用
70 | *
71 | * @param target
72 | * @param position
73 | */
74 | public void initialize(View target, int position) {
75 |
76 | int resId = getSwipeLayoutResourceId(position);
77 |
78 | OnLayoutListener onLayoutListener = new OnLayoutListener(position);
79 | ZSwipeItem swipeLayout = (ZSwipeItem) target.findViewById(resId);
80 | if (swipeLayout == null)
81 | throw new IllegalStateException(
82 | "can not find SwipeLayout in target view");
83 |
84 | SwipeMemory swipeMemory = new SwipeMemory(position);
85 | // 添加滑动监听器
86 | swipeLayout.addSwipeListener(swipeMemory);
87 | // 添加布局监听器
88 | swipeLayout.addOnLayoutListener(onLayoutListener);
89 | swipeLayout.setTag(resId, new ValueBox(position, swipeMemory,
90 | onLayoutListener));
91 |
92 | mShownLayouts.add(swipeLayout);
93 |
94 | }
95 |
96 | /**
97 | * 复用item布局的时候调用
98 | *
99 | * @param target
100 | * @param position
101 | */
102 | public void updateConvertView(View target, int position) {
103 |
104 | int resId = getSwipeLayoutResourceId(position);
105 |
106 | ZSwipeItem swipeLayout = (ZSwipeItem) target.findViewById(resId);
107 | if (swipeLayout == null)
108 | throw new IllegalStateException(
109 | "can not find SwipeLayout in target view");
110 |
111 | ValueBox valueBox = (ValueBox) swipeLayout.getTag(resId);
112 | valueBox.swipeMemory.setPosition(position);
113 | valueBox.onLayoutListener.setPosition(position);
114 | valueBox.position = position;
115 |
116 | Log.d(TAG, "updateConvertView=" + position);
117 |
118 | }
119 |
120 | private void closeAllExcept(ZSwipeItem layout) {
121 |
122 | for (ZSwipeItem s : mShownLayouts) {
123 | if (s != layout)
124 | s.close();
125 | }
126 | }
127 |
128 | /**
129 | * 获取打开的所有的item的position信息
130 | *
131 | * @return
132 | */
133 | public List getOpenItems() {
134 |
135 | if (mode == Mode.Multiple) {
136 | return new ArrayList(openPositions);
137 | } else {
138 | return Arrays.asList(openPosition);
139 | }
140 | }
141 |
142 | /**
143 | * position位置的item是否打开
144 | *
145 | * @param position
146 | * @return
147 | */
148 | public boolean isOpen(int position) {
149 | if (mode == Mode.Multiple) {
150 | return openPositions.contains(position);
151 | } else {
152 | return openPosition == position;
153 | }
154 | }
155 |
156 | public Mode getMode() {
157 | return mode;
158 | }
159 |
160 | public void setMode(Mode mode) {
161 | this.mode = mode;
162 | openPositions.clear();
163 | mShownLayouts.clear();
164 | openPosition = INVALID_POSITION;
165 | }
166 |
167 | class ValueBox {
168 | OnLayoutListener onLayoutListener;
169 | SwipeMemory swipeMemory;
170 | int position;
171 |
172 | ValueBox(int position, SwipeMemory swipeMemory,
173 | OnLayoutListener onLayoutListener) {
174 | this.swipeMemory = swipeMemory;
175 | this.onLayoutListener = onLayoutListener;
176 | this.position = position;
177 | }
178 | }
179 |
180 | private class OnLayoutListener implements OnSwipeLayoutListener {
181 |
182 | private int position;
183 |
184 | OnLayoutListener(int position) {
185 | this.position = position;
186 | }
187 |
188 | public void setPosition(int position) {
189 | this.position = position;
190 | }
191 |
192 | @Override
193 | public void onLayout(ZSwipeItem v) {
194 |
195 | if (isOpen(position)) {
196 | v.open(false, false);
197 | } else {
198 | v.close(false, false);
199 | }
200 | }
201 | }
202 |
203 | class SwipeMemory extends SimpleSwipeListener {
204 |
205 | private int position;
206 |
207 | SwipeMemory(int position) {
208 | this.position = position;
209 | }
210 |
211 | @Override
212 | public void onClose(ZSwipeItem layout) {
213 |
214 | if (mode == Mode.Multiple) {
215 | openPositions.remove(position);
216 | } else {
217 | openPosition = INVALID_POSITION;
218 | }
219 | }
220 |
221 | @Override
222 | public void onStartOpen(ZSwipeItem layout) {
223 |
224 | if (mode == Mode.Single) {
225 | closeAllExcept(layout);
226 | }
227 | }
228 |
229 | @Override
230 | public void onOpen(ZSwipeItem layout) {
231 |
232 | if (mode == Mode.Multiple)
233 | openPositions.add(position);
234 | else {
235 | closeAllExcept(layout);
236 | openPosition = position;
237 | }
238 | }
239 |
240 | public void setPosition(int position) {
241 | this.position = position;
242 | }
243 | }
244 |
245 | }
246 |
--------------------------------------------------------------------------------
/src/com/socks/autoload/zlistview/enums/DragEdge.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014, 青岛司通科技有限公司 All rights reserved.
3 | * File Name:a.java
4 | * Version:V1.0
5 | * Author:zhaokaiqiang
6 | * Date:2015-1-6
7 | */
8 |
9 | package com.socks.autoload.zlistview.enums;
10 |
11 | /**
12 | * 接收拖动方向
13 | *
14 | * @class: com.socks.zlistview.bean.DragEdge
15 | * @author zhaokaiqiang
16 | * @date 2015-1-7 下午4:18:28
17 | *
18 | */
19 | public enum DragEdge {
20 | Left, Right, Top, Bottom;
21 | };
--------------------------------------------------------------------------------
/src/com/socks/autoload/zlistview/enums/Mode.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014, 青岛司通科技有限公司 All rights reserved.
3 | * File Name:Mode.java
4 | * Version:V1.0
5 | * Author:zhaokaiqiang
6 | * Date:2015-1-7
7 | */
8 |
9 | package com.socks.autoload.zlistview.enums;
10 |
11 | /**
12 | * 单一模式、多开模式
13 | *
14 | * @class: com.socks.zlistview.bean.Mode
15 | * @author zhaokaiqiang
16 | * @date 2015-1-8 上午9:04:41
17 | *
18 | */
19 | public enum Mode {
20 | Single, Multiple;
21 | };
22 |
--------------------------------------------------------------------------------
/src/com/socks/autoload/zlistview/enums/ShowMode.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014, 青岛司通科技有限公司 All rights reserved.
3 | * File Name:ShowMode.java
4 | * Version:V1.0
5 | * Author:zhaokaiqiang
6 | * Date:2015-1-6
7 | */
8 |
9 | package com.socks.autoload.zlistview.enums;
10 |
11 | /**
12 | * 显示模式,LayDown为覆盖,PullOut为推出
13 | *
14 | * @class: com.socks.zlistview.bean.ShowMode
15 | * @author zhaokaiqiang
16 | * @date 2015-1-6 下午5:47:32
17 | *
18 | */
19 | public enum ShowMode {
20 | LayDown, PullOut;
21 | }
22 |
--------------------------------------------------------------------------------
/src/com/socks/autoload/zlistview/listener/OnSwipeLayoutListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014, 青岛司通科技有限公司 All rights reserved.
3 | * File Name:OnLayout.java
4 | * Version:V1.0
5 | * Author:zhaokaiqiang
6 | * Date:2015-1-6
7 | */
8 |
9 | package com.socks.autoload.zlistview.listener;
10 |
11 |
12 | import com.socks.autoload.zlistview.ZSwipeItem;
13 |
14 | public interface OnSwipeLayoutListener {
15 | public void onLayout(ZSwipeItem v);
16 | }
17 |
--------------------------------------------------------------------------------
/src/com/socks/autoload/zlistview/listener/SimpleSwipeListener.java:
--------------------------------------------------------------------------------
1 | package com.socks.autoload.zlistview.listener;
2 |
3 |
4 | import com.socks.autoload.zlistview.ZSwipeItem;
5 |
6 | /**
7 | * 简单实现的SwipeListener
8 | *
9 | * @class: com.socks.zlistview.listener.SimpleSwipeListener
10 | * @author zhaokaiqiang
11 | * @date 2015-1-8 上午10:09:37
12 | *
13 | */
14 | public class SimpleSwipeListener implements SwipeListener {
15 |
16 | @Override
17 | public void onStartOpen(ZSwipeItem layout) {
18 | }
19 |
20 | @Override
21 | public void onOpen(ZSwipeItem layout) {
22 | }
23 |
24 | @Override
25 | public void onStartClose(ZSwipeItem layout) {
26 | }
27 |
28 | @Override
29 | public void onClose(ZSwipeItem layout) {
30 | }
31 |
32 | @Override
33 | public void onUpdate(ZSwipeItem layout, int leftOffset, int topOffset) {
34 | }
35 |
36 | @Override
37 | public void onHandRelease(ZSwipeItem layout, float xvel, float yvel) {
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/com/socks/autoload/zlistview/listener/SwipeListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014, 青岛司通科技有限公司 All rights reserved.
3 | * File Name:SwipeListener.java
4 | * Version:V1.0
5 | * Author:zhaokaiqiang
6 | * Date:2015-1-6
7 | */
8 |
9 | package com.socks.autoload.zlistview.listener;
10 |
11 |
12 | import com.socks.autoload.zlistview.ZSwipeItem;
13 |
14 | /**
15 | * 滑动监听器
16 | *
17 | * @class: com.socks.zlistview.bean.SwipeListener
18 | * @author zhaokaiqiang
19 | * @date 2015-1-6 下午5:49:10
20 | *
21 | */
22 | public interface SwipeListener {
23 |
24 | public void onStartOpen(ZSwipeItem layout);
25 |
26 | public void onOpen(ZSwipeItem layout);
27 |
28 | public void onStartClose(ZSwipeItem layout);
29 |
30 | public void onClose(ZSwipeItem layout);
31 |
32 | public void onUpdate(ZSwipeItem layout, int leftOffset, int topOffset);
33 |
34 | public void onHandRelease(ZSwipeItem layout, float xvel, float yvel);
35 |
36 | }
37 |
--------------------------------------------------------------------------------