├── .gitignore
├── DragableRecyclerViewLib
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── zhl
│ │ └── dragablerecyclerview
│ │ ├── swipemenu
│ │ ├── SwipeMenu.java
│ │ ├── SwipeMenuAdapter.java
│ │ ├── SwipeMenuCreator.java
│ │ ├── SwipeMenuItem.java
│ │ ├── SwipeMenuLayout.java
│ │ └── SwipeMenuView.java
│ │ ├── titanic
│ │ ├── Titanic.java
│ │ └── TitanicTextView.java
│ │ ├── utils
│ │ ├── TimeType.java
│ │ └── Utils.java
│ │ └── view
│ │ ├── CBRefreshFooter.java
│ │ ├── CBRefreshHeader.java
│ │ ├── CBRefreshHeaderView.java
│ │ ├── CBRefreshState.java
│ │ └── DragableRecyclerView.java
│ └── res
│ ├── drawable-nodpi
│ └── wave.png
│ ├── drawable-xhdpi
│ ├── icon_header_refresh.png
│ ├── top_pull_refresh_arrow.png
│ └── top_search_bar.png
│ ├── drawable
│ └── footer_bg_selector.xml
│ ├── layout
│ ├── cblistview_footer.xml
│ ├── cblistview_header.xml
│ ├── cbpullrefrsh_topsearch.xml
│ └── header.xml
│ └── values
│ ├── colors.xml
│ ├── dimens.xml
│ └── strings.xml
├── GIF.gif
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── zhl
│ │ └── dragablerecyclerviewsample
│ │ ├── CustomFooter.java
│ │ ├── CustomHeader.java
│ │ └── MainActivity.java
│ └── res
│ ├── layout
│ ├── activity_main.xml
│ ├── custom_footer.xml
│ ├── custom_header.xml
│ └── item_recycler.xml
│ ├── mipmap-hdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-mdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-xhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-xxhdpi
│ ├── ic_launcher.png
│ ├── ic_launcher_round.png
│ ├── icon_collection.png
│ └── icon_delete.png
│ ├── mipmap-xxxhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ └── values
│ ├── colors.xml
│ ├── strings.xml
│ └── styles.xml
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/workspace.xml
5 | /.idea/libraries
6 | .DS_Store
7 | /build
8 | /captures
9 | .externalNativeBuild
10 |
--------------------------------------------------------------------------------
/DragableRecyclerViewLib/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/DragableRecyclerViewLib/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 25
5 | buildToolsVersion "25.0.3"
6 |
7 | defaultConfig {
8 | minSdkVersion 14
9 | targetSdkVersion 25
10 | versionCode 1
11 | versionName "1.0"
12 |
13 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
14 |
15 | }
16 | buildTypes {
17 | release {
18 | minifyEnabled false
19 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
20 | }
21 | }
22 | }
23 |
24 | dependencies {
25 | compile fileTree(include: ['*.jar'], dir: 'libs')
26 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
27 | exclude group: 'com.android.support', module: 'support-annotations'
28 | })
29 | compile 'com.android.support:appcompat-v7:25.0.1'
30 | testCompile 'junit:junit:4.12'
31 | compile 'com.android.support:recyclerview-v7:25.0.1'
32 | }
33 |
--------------------------------------------------------------------------------
/DragableRecyclerViewLib/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in D:\work\AndroidSDK/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
19 | # Uncomment this to preserve the line number information for
20 | # debugging stack traces.
21 | #-keepattributes SourceFile,LineNumberTable
22 |
23 | # If you keep the line number information, uncomment this to
24 | # hide the original source file name.
25 | #-renamesourcefileattribute SourceFile
26 |
--------------------------------------------------------------------------------
/DragableRecyclerViewLib/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/DragableRecyclerViewLib/src/main/java/com/zhl/dragablerecyclerview/swipemenu/SwipeMenu.java:
--------------------------------------------------------------------------------
1 | package com.zhl.dragablerecyclerview.swipemenu;
2 |
3 | import android.content.Context;
4 |
5 | import java.util.ArrayList;
6 | import java.util.List;
7 |
8 | public class SwipeMenu {
9 |
10 | private Context mContext;
11 | private List mItems;
12 | private int mViewType;
13 |
14 | public SwipeMenu(Context context) {
15 | mContext = context;
16 | mItems = new ArrayList();
17 | }
18 |
19 | public Context getContext() {
20 | return mContext;
21 | }
22 |
23 | public void addMenuItem(SwipeMenuItem item) {
24 | mItems.add(item);
25 | }
26 |
27 | public void removeMenuItem(SwipeMenuItem item) {
28 | mItems.remove(item);
29 | }
30 |
31 | public List getMenuItems() {
32 | return mItems;
33 | }
34 |
35 | public SwipeMenuItem getMenuItem(int index) {
36 | return mItems.get(index);
37 | }
38 |
39 | public int getViewType() {
40 | return mViewType;
41 | }
42 |
43 | public void setViewType(int viewType) {
44 | this.mViewType = viewType;
45 | }
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/DragableRecyclerViewLib/src/main/java/com/zhl/dragablerecyclerview/swipemenu/SwipeMenuAdapter.java:
--------------------------------------------------------------------------------
1 | package com.zhl.dragablerecyclerview.swipemenu;
2 |
3 | import android.content.Context;
4 | import android.support.v7.widget.GridLayoutManager;
5 | import android.support.v7.widget.RecyclerView;
6 | import android.support.v7.widget.StaggeredGridLayoutManager;
7 | import android.view.View;
8 | import android.view.ViewGroup;
9 | import android.view.animation.LinearInterpolator;
10 |
11 |
12 | public abstract class SwipeMenuAdapter extends RecyclerView.Adapter implements SwipeMenuView.OnSwipeItemClickListener {
13 | public static final int TYPE_ITEM_HEADER = 1000000;
14 | public static final int TYPE_ITEM_FOOTER = 1000001;
15 | public static final int TYPE_ITEM_CONTENT = 1000002;
16 | private RecyclerView.Adapter mAdapter;
17 | private Context mContext;
18 |
19 | public SwipeMenuAdapter(Context context, RecyclerView.Adapter adapter) {
20 | mAdapter = adapter;
21 | mContext = context;
22 | }
23 |
24 | protected abstract void createMenu(SwipeMenu menu);
25 |
26 | protected abstract boolean isPullRefreshEnable();
27 |
28 | protected abstract boolean isPullLoadMoreEnable();
29 |
30 | protected abstract View getHeaderView();
31 |
32 | protected abstract View getFooterView();
33 | // {
34 | // // Test Code
35 | // SwipeMenuItem item = new SwipeMenuItem(mContext);
36 | // item.setTitle("Item 1");
37 | // item.setBackground(new ColorDrawable(Color.GRAY));
38 | // item.setWidth(300);
39 | // menu.addMenuItem(item);
40 | //
41 | // item = new SwipeMenuItem(mContext);
42 | // item.setTitle("Item 2");
43 | // item.setBackground(new ColorDrawable(Color.RED));
44 | // item.setWidth(300);
45 | // menu.addMenuItem(item);
46 | // }
47 |
48 |
49 | @Override
50 | public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
51 | if (viewType == TYPE_ITEM_HEADER) {
52 | return new SimpleViewHolder(getHeaderView());
53 | } else if (viewType == TYPE_ITEM_FOOTER) {
54 | return new SimpleViewHolder(getFooterView());
55 | } else {
56 | RecyclerView.ViewHolder viewHolder = mAdapter.onCreateViewHolder(parent, viewType);
57 | SwipeMenu menu = new SwipeMenu(mContext);
58 | menu.setViewType(getItemViewType(viewHolder.getAdapterPosition()));
59 | createMenu(menu);
60 | SwipeMenuView menuView = new SwipeMenuView(menu);
61 | menuView.setOnSwipeItemClickListener(this);
62 | SwipeMenuLayout layout = new SwipeMenuLayout(viewHolder.itemView, menuView, new LinearInterpolator(),
63 | new LinearInterpolator());
64 | SwipeMenuViewHolder swipeMenuViewHolder = new SwipeMenuViewHolder(layout);
65 | swipeMenuViewHolder.setOrignalHolder(viewHolder);
66 | return swipeMenuViewHolder;
67 | }
68 | }
69 |
70 | @Override
71 | public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
72 | if (getItemViewType(position) == TYPE_ITEM_HEADER || getItemViewType(position) == TYPE_ITEM_FOOTER) {
73 | return;
74 | }
75 | int contentPos = position;
76 | if (isPullRefreshEnable()) {
77 | contentPos = position - 1;
78 | }
79 | ((SwipeMenuLayout) holder.itemView).setPosition(contentPos);
80 | mAdapter.onBindViewHolder(((SwipeMenuViewHolder) holder).getOrignalHolder(), contentPos);
81 | }
82 |
83 | @Override
84 | public int getItemViewType(int position) {
85 | if ((position == 0 && isPullRefreshEnable())) {
86 | return TYPE_ITEM_HEADER;
87 | } else if ((position == getItemCount() - 1 && isPullLoadMoreEnable())) {
88 | return TYPE_ITEM_FOOTER;
89 | }
90 | int contentPos = position;
91 | if (isPullRefreshEnable()) {
92 | contentPos = position - 1;
93 | }
94 | return mAdapter.getItemViewType(contentPos);
95 | }
96 |
97 | @Override
98 | public int getItemCount() {
99 | if ((isPullRefreshEnable() && !isPullLoadMoreEnable()) || (!isPullRefreshEnable() && isPullLoadMoreEnable())) {
100 | return mAdapter.getItemCount() + 1;
101 | } else if (isPullRefreshEnable() && isPullLoadMoreEnable()) {
102 | return mAdapter.getItemCount() + 2;
103 | } else {
104 | return mAdapter.getItemCount();
105 | }
106 | }
107 |
108 | @Override
109 | public void onAttachedToRecyclerView(RecyclerView recyclerView) {
110 | super.onAttachedToRecyclerView(recyclerView);
111 | RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();
112 | if (manager instanceof GridLayoutManager) {
113 | final GridLayoutManager gridManager = ((GridLayoutManager) manager);
114 | gridManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
115 | @Override
116 | public int getSpanSize(int position) {
117 | return (isHeader(position) || isFooter(position))
118 | ? gridManager.getSpanCount() : 1;
119 | }
120 | });
121 | }
122 | mAdapter.onAttachedToRecyclerView(recyclerView);
123 | }
124 |
125 | @Override
126 | public void onDetachedFromRecyclerView(RecyclerView recyclerView) {
127 | mAdapter.onDetachedFromRecyclerView(recyclerView);
128 | }
129 |
130 | @Override
131 | public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) {
132 | super.onViewAttachedToWindow(holder);
133 | ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
134 | if (lp != null
135 | && lp instanceof StaggeredGridLayoutManager.LayoutParams
136 | && (isHeader(holder.getLayoutPosition()) || isFooter(holder.getLayoutPosition()))) {
137 | StaggeredGridLayoutManager.LayoutParams p = (StaggeredGridLayoutManager.LayoutParams) lp;
138 | p.setFullSpan(true);
139 | }
140 | mAdapter.onViewAttachedToWindow(holder);
141 | }
142 |
143 | private boolean isFooter(int layoutPosition) {
144 | return getItemViewType(layoutPosition) == TYPE_ITEM_FOOTER;
145 | }
146 |
147 |
148 | private boolean isHeader(int layoutPosition) {
149 | return getItemViewType(layoutPosition) == TYPE_ITEM_HEADER;
150 | }
151 |
152 | @Override
153 | public void onViewDetachedFromWindow(RecyclerView.ViewHolder holder) {
154 | mAdapter.onViewDetachedFromWindow(holder);
155 | }
156 |
157 | @Override
158 | public void onViewRecycled(RecyclerView.ViewHolder holder) {
159 | mAdapter.onViewRecycled(holder);
160 | }
161 |
162 | @Override
163 | public boolean onFailedToRecycleView(RecyclerView.ViewHolder holder) {
164 | return mAdapter.onFailedToRecycleView(holder);
165 | }
166 |
167 | @Override
168 | public void registerAdapterDataObserver(RecyclerView.AdapterDataObserver observer) {
169 | mAdapter.registerAdapterDataObserver(observer);
170 | }
171 |
172 | @Override
173 | public void unregisterAdapterDataObserver(RecyclerView.AdapterDataObserver observer) {
174 | mAdapter.unregisterAdapterDataObserver(observer);
175 | }
176 |
177 | @Override
178 | public void onItemClick(SwipeMenuView view, SwipeMenu menu, int index) {
179 |
180 | }
181 |
182 | private class SimpleViewHolder extends RecyclerView.ViewHolder {
183 | public SimpleViewHolder(View itemView) {
184 | super(itemView);
185 | }
186 | }
187 |
188 | public class SwipeMenuViewHolder extends RecyclerView.ViewHolder {
189 | private RecyclerView.ViewHolder orignalHolder;
190 |
191 | public SwipeMenuViewHolder(View itemView) {
192 | super(itemView);
193 | }
194 |
195 | public RecyclerView.ViewHolder getOrignalHolder() {
196 | return orignalHolder;
197 | }
198 |
199 | public void setOrignalHolder(RecyclerView.ViewHolder orignalHolder) {
200 | this.orignalHolder = orignalHolder;
201 | }
202 | }
203 |
204 | }
205 |
--------------------------------------------------------------------------------
/DragableRecyclerViewLib/src/main/java/com/zhl/dragablerecyclerview/swipemenu/SwipeMenuCreator.java:
--------------------------------------------------------------------------------
1 | package com.zhl.dragablerecyclerview.swipemenu;
2 |
3 | public interface SwipeMenuCreator {
4 |
5 | void create(SwipeMenu menu);
6 | }
7 |
--------------------------------------------------------------------------------
/DragableRecyclerViewLib/src/main/java/com/zhl/dragablerecyclerview/swipemenu/SwipeMenuItem.java:
--------------------------------------------------------------------------------
1 | package com.zhl.dragablerecyclerview.swipemenu;
2 |
3 | import android.content.Context;
4 | import android.graphics.drawable.Drawable;
5 |
6 | public class SwipeMenuItem {
7 |
8 | private int id;
9 | private Context mContext;
10 | private String title;
11 | private Drawable icon;
12 | private Drawable background;
13 | private int titleColor;
14 | private int titleSize;
15 | private int width;
16 |
17 | public SwipeMenuItem(Context context) {
18 | mContext = context;
19 | }
20 |
21 | public int getId() {
22 | return id;
23 | }
24 |
25 | public void setId(int id) {
26 | this.id = id;
27 | }
28 |
29 | public int getTitleColor() {
30 | return titleColor;
31 | }
32 |
33 | public int getTitleSize() {
34 | return titleSize;
35 | }
36 |
37 | public void setTitleSize(int titleSize) {
38 | this.titleSize = titleSize;
39 | }
40 |
41 | public void setTitleColor(int titleColor) {
42 | this.titleColor = titleColor;
43 | }
44 |
45 | public String getTitle() {
46 | return title;
47 | }
48 |
49 | public void setTitle(String title) {
50 | this.title = title;
51 | }
52 |
53 | public void setTitle(int resId) {
54 | setTitle(mContext.getString(resId));
55 | }
56 |
57 | public Drawable getIcon() {
58 | return icon;
59 | }
60 |
61 | public void setIcon(Drawable icon) {
62 | this.icon = icon;
63 | }
64 |
65 | public void setIcon(int resId) {
66 | this.icon = mContext.getResources().getDrawable(resId);
67 | }
68 |
69 | public Drawable getBackground() {
70 | return background;
71 | }
72 |
73 | public void setBackground(Drawable background) {
74 | this.background = background;
75 | }
76 |
77 | public void setBackground(int resId) {
78 | this.background = mContext.getResources().getDrawable(resId);
79 | }
80 |
81 | public int getWidth() {
82 | return width;
83 | }
84 |
85 | public void setWidth(int width) {
86 | this.width = width;
87 | }
88 |
89 | }
90 |
--------------------------------------------------------------------------------
/DragableRecyclerViewLib/src/main/java/com/zhl/dragablerecyclerview/swipemenu/SwipeMenuLayout.java:
--------------------------------------------------------------------------------
1 | package com.zhl.dragablerecyclerview.swipemenu;
2 |
3 | import android.content.Context;
4 | import android.support.v4.view.GestureDetectorCompat;
5 | import android.support.v4.widget.ScrollerCompat;
6 | import android.support.v7.widget.RecyclerView;
7 | import android.util.AttributeSet;
8 | import android.util.Log;
9 | import android.util.TypedValue;
10 | import android.view.GestureDetector;
11 | import android.view.MotionEvent;
12 | import android.view.View;
13 | import android.view.ViewGroup;
14 | import android.view.animation.Interpolator;
15 | import android.widget.AbsListView;
16 | import android.widget.FrameLayout;
17 |
18 | public class SwipeMenuLayout extends FrameLayout {
19 |
20 | private static final int CONTENT_VIEW_ID = 1;
21 | private static final int MENU_VIEW_ID = 2;
22 |
23 | private static final int STATE_CLOSE = 0;
24 | private static final int STATE_OPEN = 1;
25 |
26 | private View mContentView;
27 | private SwipeMenuView mMenuView;
28 | private int mDownX;
29 | private int state = STATE_CLOSE;
30 | private GestureDetectorCompat mGestureDetector;
31 | private GestureDetector.OnGestureListener mGestureListener;
32 | private boolean isFling;
33 | private int MIN_FLING = dp2px(15);
34 | private int MAX_VELOCITYX = -dp2px(500);
35 | private ScrollerCompat mOpenScroller;
36 | private ScrollerCompat mCloseScroller;
37 | private int mBaseX;
38 | private int position;
39 | private Interpolator mCloseInterpolator;
40 | private Interpolator mOpenInterpolator;
41 |
42 | public SwipeMenuLayout(View contentView, SwipeMenuView menuView) {
43 | this(contentView, menuView, null, null);
44 | }
45 |
46 | public SwipeMenuLayout(View contentView, SwipeMenuView menuView, Interpolator closeInterpolator,
47 | Interpolator openInterpolator) {
48 | super(contentView.getContext());
49 | mCloseInterpolator = closeInterpolator;
50 | mOpenInterpolator = openInterpolator;
51 | mContentView = contentView;
52 | mMenuView = menuView;
53 | mMenuView.setLayout(this);
54 | init();
55 | }
56 |
57 | private SwipeMenuLayout(Context context, AttributeSet attrs) {
58 | super(context, attrs);
59 | }
60 |
61 | private SwipeMenuLayout(Context context) {
62 | super(context);
63 | }
64 |
65 | public int getPosition() {
66 | return position;
67 | }
68 |
69 | public void setPosition(int position) {
70 | this.position = position;
71 | mMenuView.setPosition(position);
72 | }
73 |
74 | private void init() {
75 | setLayoutParams(new RecyclerView.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
76 | mGestureListener = new GestureDetector.SimpleOnGestureListener() {
77 | @Override
78 | public boolean onDown(MotionEvent e) {
79 | isFling = false;
80 | return true;
81 | }
82 |
83 | @Override
84 | public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
85 | // TODO
86 | if ((e1.getX() - e2.getX()) > MIN_FLING && velocityX < MAX_VELOCITYX) {
87 | isFling = true;
88 | }
89 | // Log.i("byz", MAX_VELOCITYX + ", velocityX = " + velocityX);
90 | return super.onFling(e1, e2, velocityX, velocityY);
91 | }
92 | };
93 | mGestureDetector = new GestureDetectorCompat(getContext(), mGestureListener);
94 |
95 | if (mCloseInterpolator != null) {
96 | mCloseScroller = ScrollerCompat.create(getContext(), mCloseInterpolator);
97 | } else {
98 | mCloseScroller = ScrollerCompat.create(getContext());
99 | }
100 | if (mOpenInterpolator != null) {
101 | mOpenScroller = ScrollerCompat.create(getContext(), mOpenInterpolator);
102 | } else {
103 | mOpenScroller = ScrollerCompat.create(getContext());
104 | }
105 |
106 | LayoutParams contentParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
107 | mContentView.setLayoutParams(contentParams);
108 | if (mContentView.getId() < 1) {
109 | mContentView.setId(CONTENT_VIEW_ID);
110 | }
111 |
112 | mMenuView.setId(MENU_VIEW_ID);
113 | mMenuView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT));
114 |
115 | addView(mContentView);
116 | addView(mMenuView);
117 |
118 | }
119 |
120 | @Override
121 | protected void onAttachedToWindow() {
122 | super.onAttachedToWindow();
123 | }
124 |
125 | @Override
126 | protected void onSizeChanged(int w, int h, int oldw, int oldh) {
127 | super.onSizeChanged(w, h, oldw, oldh);
128 | }
129 |
130 | public boolean onSwipe(MotionEvent event) {
131 | mGestureDetector.onTouchEvent(event);
132 | switch (event.getAction()) {
133 | case MotionEvent.ACTION_DOWN:
134 | mDownX = (int) event.getX();
135 | isFling = false;
136 | break;
137 | case MotionEvent.ACTION_MOVE:
138 | // Log.i("byz", "downX = " + mDownX + ", moveX = " + event.getX());
139 | int dis = (int) (mDownX - event.getX());
140 | if (state == STATE_OPEN) {
141 | dis += mMenuView.getWidth();
142 | }
143 | swipe(dis);
144 | break;
145 | case MotionEvent.ACTION_UP:
146 | if (isFling || (mDownX - event.getX()) > (mMenuView.getWidth() / 2)) {
147 | // open
148 | smoothOpenMenu();
149 | } else {
150 | // close
151 | smoothCloseMenu();
152 | return false;
153 | }
154 | break;
155 | }
156 | return false;
157 | }
158 |
159 | /**
160 | * 滑动侧滑菜单
161 | * @param dis
162 | */
163 | public void swipeMenuSlide(int dis){
164 | if (state == STATE_OPEN) {
165 | dis += mMenuView.getWidth();
166 | }
167 | swipe(dis);
168 | }
169 |
170 | /**
171 | * 手指快速滑动的时候是打开还是关闭侧滑菜单
172 | * @param isFling
173 | * @param dix
174 | */
175 | public void swipeMenuFling(boolean isFling,int dix){
176 | if (isFling || dix > (mMenuView.getWidth() / 2)) {
177 | // open
178 | smoothOpenMenu();
179 | } else {
180 | // close
181 | smoothCloseMenu();
182 | }
183 | }
184 |
185 |
186 | public boolean isOpen() {
187 | return state == STATE_OPEN;
188 | }
189 |
190 | public boolean isActive() {
191 | if (mContentView != null) {
192 | return mContentView.getLeft() != 0;
193 | }
194 | return false;
195 | }
196 |
197 | @Override
198 | public boolean onTouchEvent(MotionEvent event) {
199 | return super.onTouchEvent(event);
200 | }
201 |
202 | private void swipe(int dis) {
203 | if (dis > mMenuView.getWidth()) {
204 | dis = mMenuView.getWidth();
205 | }
206 | if (dis < 0) {
207 | dis = 0;
208 | }
209 | mContentView.layout(-dis, mContentView.getTop(), mContentView.getWidth() - dis, getMeasuredHeight());
210 | mMenuView.layout(mContentView.getWidth() - dis, mMenuView.getTop(),
211 | mContentView.getWidth() + mMenuView.getWidth() - dis, getMeasuredHeight());
212 | }
213 |
214 | @Override
215 | public void computeScroll() {
216 | if (state == STATE_OPEN) {
217 | if (mOpenScroller.computeScrollOffset()) {
218 | swipe(mOpenScroller.getCurrX());
219 | postInvalidate();
220 | }
221 | } else {
222 | if (mCloseScroller.computeScrollOffset()) {
223 | swipe(mBaseX - mCloseScroller.getCurrX());
224 | postInvalidate();
225 | }
226 | }
227 | }
228 |
229 | public void smoothCloseMenu() {
230 | state = STATE_CLOSE;
231 | mBaseX = -mContentView.getLeft();
232 | mCloseScroller.startScroll(0, 0, mBaseX, 0, 350);
233 | postInvalidate();
234 | }
235 |
236 | public void smoothOpenMenu() {
237 | state = STATE_OPEN;
238 | mOpenScroller.startScroll(-mContentView.getLeft(), 0, mMenuView.getWidth(), 0, 350);
239 | postInvalidate();
240 | }
241 |
242 | public void closeMenu() {
243 | if (mCloseScroller.computeScrollOffset()) {
244 | mCloseScroller.abortAnimation();
245 | }
246 | if (state == STATE_OPEN) {
247 | state = STATE_CLOSE;
248 | swipe(0);
249 | }
250 | }
251 |
252 | public void openMenu() {
253 | if (state == STATE_CLOSE) {
254 | state = STATE_OPEN;
255 | swipe(mMenuView.getWidth());
256 | }
257 | }
258 |
259 | public View getContentView() {
260 | return mContentView;
261 | }
262 |
263 | public SwipeMenuView getMenuView() {
264 | return mMenuView;
265 | }
266 |
267 | private int dp2px(int dp) {
268 | return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getContext().getResources()
269 | .getDisplayMetrics());
270 | }
271 |
272 | @Override
273 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
274 | super.onMeasure(widthMeasureSpec, heightMeasureSpec);
275 | mMenuView.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
276 | MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.EXACTLY));
277 | }
278 |
279 | @Override
280 | protected void onLayout(boolean changed, int l, int t, int r, int b) {
281 | mContentView.layout(0, 0, getMeasuredWidth(), getMeasuredHeight());
282 | mMenuView.layout(getMeasuredWidth(), 0, getMeasuredWidth() + mMenuView.getMeasuredWidth(),
283 | getMeasuredHeight());
284 | }
285 |
286 | public void setMenuHeight(int measuredHeight) {
287 | Log.i("byz", "pos = " + position + ", height = " + measuredHeight);
288 | LayoutParams params = (LayoutParams) mMenuView.getLayoutParams();
289 | if (params.height != measuredHeight) {
290 | params.height = measuredHeight;
291 | mMenuView.setLayoutParams(mMenuView.getLayoutParams());
292 | }
293 | }
294 | }
295 |
--------------------------------------------------------------------------------
/DragableRecyclerViewLib/src/main/java/com/zhl/dragablerecyclerview/swipemenu/SwipeMenuView.java:
--------------------------------------------------------------------------------
1 | package com.zhl.dragablerecyclerview.swipemenu;
2 |
3 | import android.text.TextUtils;
4 | import android.view.Gravity;
5 | import android.view.View;
6 | import android.view.View.OnClickListener;
7 | import android.widget.ImageView;
8 | import android.widget.LinearLayout;
9 | import android.widget.TextView;
10 |
11 | import java.util.List;
12 |
13 | public class SwipeMenuView extends LinearLayout implements OnClickListener {
14 |
15 | // private CBPullRefreshListView mListView;
16 | private SwipeMenuLayout mLayout;
17 | private SwipeMenu mMenu;
18 | private OnSwipeItemClickListener onItemClickListener;
19 | private int position;
20 |
21 | public int getPosition() {
22 | return position;
23 | }
24 |
25 | public void setPosition(int position) {
26 | this.position = position;
27 | }
28 |
29 | public SwipeMenuView(SwipeMenu menu) {
30 | super(menu.getContext());
31 | mMenu = menu;
32 | List items = menu.getMenuItems();
33 | int id = 0;
34 | for (SwipeMenuItem item : items) {
35 | addItem(item, id++);
36 | }
37 | }
38 |
39 | private void addItem(SwipeMenuItem item, int id) {
40 | LayoutParams params = new LayoutParams(item.getWidth(), LayoutParams.MATCH_PARENT);
41 | LinearLayout parent = new LinearLayout(getContext());
42 | parent.setId(id);
43 | parent.setGravity(Gravity.CENTER);
44 | parent.setOrientation(LinearLayout.VERTICAL);
45 | parent.setLayoutParams(params);
46 | parent.setBackgroundDrawable(item.getBackground());
47 | parent.setOnClickListener(this);
48 | if (item.getIcon() != null) {
49 | parent.addView(createIcon(item));
50 | }
51 | if (!TextUtils.isEmpty(item.getTitle())) {
52 | parent.addView(createTitle(item));
53 | }
54 | addView(parent);
55 | }
56 |
57 | private ImageView createIcon(SwipeMenuItem item) {
58 | ImageView iv = new ImageView(getContext());
59 | iv.setImageDrawable(item.getIcon());
60 | return iv;
61 | }
62 |
63 | private TextView createTitle(SwipeMenuItem item) {
64 | TextView tv = new TextView(getContext());
65 | tv.setText(item.getTitle());
66 | tv.setGravity(Gravity.CENTER);
67 | tv.setTextSize(item.getTitleSize());
68 | tv.setTextColor(item.getTitleColor());
69 | return tv;
70 | }
71 |
72 | @Override
73 | public void onClick(View v) {
74 | if (onItemClickListener != null && mLayout.isOpen()) {
75 | onItemClickListener.onItemClick(this, mMenu, v.getId());
76 | }
77 | }
78 |
79 | public OnSwipeItemClickListener getOnSwipeItemClickListener() {
80 | return onItemClickListener;
81 | }
82 |
83 | public void setOnSwipeItemClickListener(OnSwipeItemClickListener onItemClickListener) {
84 | this.onItemClickListener = onItemClickListener;
85 | }
86 |
87 | public void setLayout(SwipeMenuLayout mLayout) {
88 | this.mLayout = mLayout;
89 | }
90 |
91 | public static interface OnSwipeItemClickListener {
92 | void onItemClick(SwipeMenuView view, SwipeMenu menu, int index);
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/DragableRecyclerViewLib/src/main/java/com/zhl/dragablerecyclerview/titanic/Titanic.java:
--------------------------------------------------------------------------------
1 | package com.zhl.dragablerecyclerview.titanic;
2 |
3 | import android.animation.Animator;
4 | import android.animation.AnimatorSet;
5 | import android.animation.ObjectAnimator;
6 | import android.animation.ValueAnimator;
7 | import android.annotation.SuppressLint;
8 | import android.os.Build;
9 | import android.view.animation.LinearInterpolator;
10 |
11 |
12 | public class Titanic {
13 |
14 | private AnimatorSet animatorSet;
15 | private Animator.AnimatorListener animatorListener;
16 |
17 | public Animator.AnimatorListener getAnimatorListener() {
18 | return animatorListener;
19 | }
20 |
21 | public void setAnimatorListener(Animator.AnimatorListener animatorListener) {
22 | this.animatorListener = animatorListener;
23 | }
24 |
25 | public void start(final TitanicTextView textView) {
26 |
27 | final Runnable animate = new Runnable() {
28 | @Override
29 | public void run() {
30 |
31 | textView.setSinking(true);
32 |
33 | // horizontal animation. 200 = wave.png width
34 | ObjectAnimator maskXAnimator = ObjectAnimator.ofFloat(textView, "maskX", 0, 200);
35 | maskXAnimator.setRepeatCount(ValueAnimator.INFINITE);
36 | maskXAnimator.setDuration(1000);
37 | maskXAnimator.setStartDelay(0);
38 |
39 | int h = textView.getHeight();
40 |
41 | // vertical animation
42 | // maskY = 0 -> wave vertically centered
43 | // repeat mode REVERSE to go back and forth
44 | ObjectAnimator maskYAnimator = ObjectAnimator.ofFloat(textView, "maskY", h/2, -h/2);
45 | maskYAnimator.setRepeatCount(ValueAnimator.INFINITE);
46 | maskYAnimator.setRepeatMode(ValueAnimator.REVERSE);
47 | maskYAnimator.setDuration(8000);
48 | maskYAnimator.setStartDelay(0);
49 |
50 | // now play both animations together
51 | animatorSet = new AnimatorSet();
52 | animatorSet.playTogether(maskXAnimator, maskYAnimator);
53 | animatorSet.setInterpolator(new LinearInterpolator());
54 | animatorSet.addListener(new Animator.AnimatorListener() {
55 | @Override
56 | public void onAnimationStart(Animator animation) {
57 | }
58 |
59 | @SuppressLint("NewApi")
60 | @Override
61 | public void onAnimationEnd(Animator animation) {
62 | textView.setSinking(false);
63 |
64 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
65 | textView.postInvalidate();
66 | } else {
67 | textView.postInvalidateOnAnimation();
68 | }
69 |
70 | animatorSet = null;
71 | }
72 |
73 | @Override
74 | public void onAnimationCancel(Animator animation) {
75 |
76 | }
77 |
78 | @Override
79 | public void onAnimationRepeat(Animator animation) {
80 |
81 | }
82 | });
83 |
84 |
85 | if (animatorListener != null) {
86 | animatorSet.addListener(animatorListener);
87 | }
88 |
89 | animatorSet.start();
90 | }
91 | };
92 |
93 | if (!textView.isSetUp()) {
94 | textView.setAnimationSetupCallback(new TitanicTextView.AnimationSetupCallback() {
95 | @Override
96 | public void onSetupAnimation(final TitanicTextView target) {
97 | animate.run();
98 | }
99 | });
100 | } else {
101 | animate.run();
102 | }
103 | }
104 |
105 | public void cancel() {
106 | if (animatorSet != null) {
107 | animatorSet.cancel();
108 | }
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/DragableRecyclerViewLib/src/main/java/com/zhl/dragablerecyclerview/titanic/TitanicTextView.java:
--------------------------------------------------------------------------------
1 | package com.zhl.dragablerecyclerview.titanic;
2 |
3 |
4 | import android.content.Context;
5 | import android.content.res.ColorStateList;
6 | import android.graphics.Bitmap;
7 | import android.graphics.BitmapShader;
8 | import android.graphics.Canvas;
9 | import android.graphics.Matrix;
10 | import android.graphics.Shader;
11 | import android.graphics.drawable.Drawable;
12 | import android.util.AttributeSet;
13 | import android.widget.TextView;
14 |
15 | import com.zhl.dragablerecyclerview.R;
16 |
17 |
18 | public class TitanicTextView extends TextView {
19 |
20 | public interface AnimationSetupCallback {
21 | public void onSetupAnimation(TitanicTextView titanicTextView);
22 | }
23 |
24 | // callback fired at first onSizeChanged
25 | private AnimationSetupCallback animationSetupCallback;
26 | // wave shader coordinates
27 | private float maskX, maskY;
28 | // if true, the shader will display the wave
29 | private boolean sinking;
30 | // true after the first onSizeChanged
31 | private boolean setUp;
32 |
33 | // shader containing a repeated wave
34 | private BitmapShader shader;
35 | // shader matrix
36 | private Matrix shaderMatrix;
37 | // wave drawable
38 | private Drawable wave;
39 | // (getHeight() - waveHeight) / 2
40 | private float offsetY;
41 |
42 | public TitanicTextView(Context context) {
43 | super(context);
44 | init();
45 | }
46 |
47 | public TitanicTextView(Context context, AttributeSet attrs) {
48 | super(context, attrs);
49 | init();
50 | }
51 |
52 | public TitanicTextView(Context context, AttributeSet attrs, int defStyle) {
53 | super(context, attrs, defStyle);
54 | init();
55 | }
56 |
57 | private void init() {
58 | shaderMatrix = new Matrix();
59 | }
60 |
61 | public AnimationSetupCallback getAnimationSetupCallback() {
62 | return animationSetupCallback;
63 | }
64 |
65 | public void setAnimationSetupCallback(AnimationSetupCallback animationSetupCallback) {
66 | this.animationSetupCallback = animationSetupCallback;
67 | }
68 |
69 | public float getMaskX() {
70 | return maskX;
71 | }
72 |
73 | public void setMaskX(float maskX) {
74 | this.maskX = maskX;
75 | invalidate();
76 | }
77 |
78 | public float getMaskY() {
79 | return maskY;
80 | }
81 |
82 | public void setMaskY(float maskY) {
83 | this.maskY = maskY;
84 | invalidate();
85 | }
86 |
87 | public boolean isSinking() {
88 | return sinking;
89 | }
90 |
91 | public void setSinking(boolean sinking) {
92 | this.sinking = sinking;
93 | }
94 |
95 | public boolean isSetUp() {
96 | return setUp;
97 | }
98 |
99 | @Override
100 | public void setTextColor(int color) {
101 | super.setTextColor(color);
102 | createShader();
103 | }
104 |
105 | @Override
106 | public void setTextColor(ColorStateList colors) {
107 | super.setTextColor(colors);
108 | createShader();
109 | }
110 |
111 | @Override
112 | protected void onSizeChanged(int w, int h, int oldw, int oldh) {
113 | super.onSizeChanged(w, h, oldw, oldh);
114 |
115 | createShader();
116 |
117 | if (!setUp) {
118 | setUp = true;
119 | if (animationSetupCallback != null) {
120 | animationSetupCallback.onSetupAnimation(TitanicTextView.this);
121 | }
122 | }
123 | }
124 |
125 | /**
126 | * Create the shader
127 | * draw the wave with current color for a background
128 | * repeat the bitmap horizontally, and clamp colors vertically
129 | */
130 | private void createShader() {
131 |
132 | if (wave == null) {
133 | wave = getResources().getDrawable(R.drawable.wave);
134 | }
135 |
136 | int waveW = wave.getIntrinsicWidth();
137 | int waveH = wave.getIntrinsicHeight();
138 |
139 | Bitmap b = Bitmap.createBitmap(waveW, waveH, Bitmap.Config.ARGB_8888);
140 | Canvas c = new Canvas(b);
141 |
142 | c.drawColor(getCurrentTextColor());
143 |
144 | wave.setBounds(0, 0, waveW, waveH);
145 | wave.draw(c);
146 |
147 | shader = new BitmapShader(b, Shader.TileMode.REPEAT, Shader.TileMode.CLAMP);
148 | getPaint().setShader(shader);
149 |
150 | offsetY = (getHeight() - waveH) / 2;
151 | }
152 |
153 | @Override
154 | protected void onDraw(Canvas canvas) {
155 |
156 | // modify text paint shader according to sinking state
157 | if (sinking && shader != null) {
158 |
159 | // first call after sinking, assign it to our paint
160 | if (getPaint().getShader() == null) {
161 | getPaint().setShader(shader);
162 | }
163 |
164 | // translate shader accordingly to maskX maskY positions
165 | // maskY is affected by the offset to vertically center the wave
166 | shaderMatrix.setTranslate(maskX, maskY + offsetY);
167 |
168 | // assign matrix to invalidate the shader
169 | shader.setLocalMatrix(shaderMatrix);
170 | } else {
171 | getPaint().setShader(null);
172 | }
173 |
174 | super.onDraw(canvas);
175 | }
176 | }
177 |
--------------------------------------------------------------------------------
/DragableRecyclerViewLib/src/main/java/com/zhl/dragablerecyclerview/utils/TimeType.java:
--------------------------------------------------------------------------------
1 | package com.zhl.dragablerecyclerview.utils;
2 |
3 | public enum TimeType {
4 | /**
5 | * yyyy-MM-dd hh:mm:ss
6 | */
7 | DEFAULT,
8 |
9 | /**
10 | * yyyyMMdd hhmmss
11 | */
12 | DEFAULT_CHINESS,
13 |
14 | /**
15 | * MM-dd HH:mm
16 | */
17 | DEFAULT_SHORT,
18 |
19 | /**
20 | * MMddhhmm
21 | */
22 | DEFAULT_CHINESS_SHORT,
23 |
24 | FROMNOW,
25 |
26 | DEFAULT_YEAR;
27 | }
--------------------------------------------------------------------------------
/DragableRecyclerViewLib/src/main/java/com/zhl/dragablerecyclerview/utils/Utils.java:
--------------------------------------------------------------------------------
1 | package com.zhl.dragablerecyclerview.utils;
2 |
3 | import android.content.Context;
4 |
5 | import com.zhl.dragablerecyclerview.R;
6 |
7 | import java.text.SimpleDateFormat;
8 | import java.util.Date;
9 | import java.util.Locale;
10 |
11 | /**
12 | * Created by zhaohl on 2016-3-24.
13 | */
14 | public class Utils {
15 | public static String getTimeDifferent(Context context,long time) {
16 | String updateTime = "";
17 | Date currentTime = new Date(System.currentTimeMillis());
18 | Date inputTime = new Date(time);
19 | long interval = currentTime.getTime() - inputTime.getTime();
20 | long days = interval / 86400000;
21 | long hours = (interval - days * 86400000) / 3600000;
22 | long minutes = (interval - days * 86400000 - hours * 3600000) / 60000;
23 | if (days >= 1) {
24 | updateTime = getPublishTime(context,TimeType.DEFAULT_YEAR, inputTime.getTime());
25 | } else if (hours >= 1) {
26 | updateTime = hours +context.getString(R.string.util_hours_ago) ;
27 | } else {
28 | if (minutes <= 10) {
29 | updateTime = context.getString(R.string.util_a_moment_ago);
30 | } else if (minutes > 10 && minutes <= 20) {
31 | updateTime = context.getString(R.string.util_10_moment_ago);
32 | } else if (minutes > 20 && minutes <= 30) {
33 | updateTime = context.getString(R.string.util_20_moment_ago);
34 | } else if (minutes > 30 && minutes < 60) {
35 | updateTime = context.getString(R.string.util_30_moment_ago);
36 | }
37 | }
38 | return updateTime;
39 | }
40 |
41 | public static String getPublishTime(Context context ,TimeType type, long time) {
42 | if (time == 0)
43 | return "";
44 | Date date = new Date(time);
45 | SimpleDateFormat dateFormat;
46 | String timeStr = null;
47 | switch (type) {
48 | case DEFAULT:
49 | dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA);
50 | timeStr = dateFormat.format(date);
51 | break;
52 | case DEFAULT_CHINESS:
53 | dateFormat = new SimpleDateFormat(context.getString(R.string.util_format_yyyymmdd_hhmmss), Locale.CHINA);
54 | timeStr = dateFormat.format(date);
55 | break;
56 | case DEFAULT_SHORT:
57 | dateFormat = new SimpleDateFormat("MM-dd HH:mm", Locale.CHINA);
58 | timeStr = dateFormat.format(date);
59 | break;
60 | case DEFAULT_CHINESS_SHORT:
61 | dateFormat = new SimpleDateFormat(context.getString(R.string.util_format_mmdd_hhmm), Locale.CHINA);
62 | timeStr = dateFormat.format(date);
63 | break;
64 | case FROMNOW:
65 | timeStr = getTimeFromNow(context,time);
66 | break;
67 | case DEFAULT_YEAR:
68 | dateFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.CHINA);
69 | timeStr = dateFormat.format(date);
70 | break;
71 | }
72 | return timeStr;
73 | }
74 |
75 | public static String getTimeFromNow(Context context,long time) {
76 | String updateTime = "";
77 | long currentTime = System.currentTimeMillis();
78 | long interval = currentTime - time;
79 | long minutes = interval / 60000;
80 | if (minutes < 60) {
81 | minutes = minutes == 0 ? 1 : minutes;
82 | updateTime = minutes + context.getString(R.string.util_miniutes_ago);
83 | } else {
84 | minutes = minutes / 60;
85 | minutes = minutes == 0 ? 1 : minutes;
86 | if (minutes < 24) {
87 | updateTime = minutes + context.getString(R.string.util_hours_ago);
88 | } else {
89 | minutes = minutes / 24;
90 | minutes = minutes == 0 ? 1 : minutes;
91 | updateTime = minutes + context.getString(R.string.util_day_ago);
92 | }
93 | }
94 | return updateTime;
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/DragableRecyclerViewLib/src/main/java/com/zhl/dragablerecyclerview/view/CBRefreshFooter.java:
--------------------------------------------------------------------------------
1 | package com.zhl.dragablerecyclerview.view;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 | import android.view.Gravity;
6 | import android.view.LayoutInflater;
7 | import android.view.View;
8 | import android.widget.LinearLayout;
9 | import android.widget.RelativeLayout;
10 | import android.widget.TextView;
11 |
12 | import com.zhl.dragablerecyclerview.R;
13 |
14 |
15 | public class CBRefreshFooter extends CBRefreshHeaderView {
16 |
17 | private Context mContext;
18 | private LinearLayout footerViewContanier;
19 | private RelativeLayout mContentView;
20 | private View mProgressBar;
21 | private TextView mHintView;
22 | private int state;
23 |
24 | public CBRefreshFooter(Context context) {
25 | super(context);
26 | initView(context);
27 | }
28 |
29 | public CBRefreshFooter(Context context, AttributeSet attrs) {
30 | super(context, attrs);
31 | initView(context);
32 | }
33 |
34 | @Override
35 | public void setState(int state) {
36 | this.state = state;
37 | }
38 |
39 | @Override
40 | public int getState() {
41 | return state;
42 | }
43 |
44 | private void initView(Context context) {
45 | LinearLayout.LayoutParams params =new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, 0);
46 | mContext = context;
47 | footerViewContanier = (LinearLayout) LayoutInflater.from(mContext).inflate(R.layout.cblistview_footer, null);
48 | mContentView = (RelativeLayout) footerViewContanier.findViewById(R.id.cbrefresh_footer_content);
49 | addView(footerViewContanier,params);
50 | setGravity(Gravity.TOP);
51 | mProgressBar = footerViewContanier.findViewById(R.id.cbrefresh_footer_progressbar);
52 | mHintView = (TextView) footerViewContanier.findViewById(R.id.cbrefresh_footer_hint_textview);
53 | }
54 |
55 | /**
56 | * set the footer bg
57 | *
58 | * @param resName
59 | */
60 | public void setFooterBg(int resName) {
61 | this.setBackgroundResource(resName);
62 | }
63 |
64 | @Override
65 | public void pullUpToLoadmore() {
66 | mProgressBar.setVisibility(View.GONE);
67 | mHintView.setVisibility(View.VISIBLE);
68 | mHintView.setText(getString(R.string.refresh_footer_tip_pullup_loadmore));
69 | }
70 |
71 | @Override
72 | public void releaseToLoadmore() {
73 | mProgressBar.setVisibility(View.GONE);
74 | mHintView.setVisibility(View.VISIBLE);
75 | mHintView.setText(getString(R.string.refresh_footer_tip_release_loadmore));
76 | }
77 |
78 | @Override
79 | public void onLoading() {
80 | mProgressBar.setVisibility(View.VISIBLE);
81 | mHintView.setVisibility(View.VISIBLE);
82 | mHintView.setText(getString(R.string.refresh_footer_tip_loading));
83 | }
84 |
85 | @Override
86 | public void onStyleChange(int state) {
87 | super.onStyleChange(state);
88 | }
89 |
90 | @Override
91 | public int getLoadMorePullUpDistance() {
92 | return footerViewContanier.getHeight();
93 | }
94 |
95 | @Override
96 | public void setLoadMorePullUpDistance(int deltaY) {
97 | if (deltaY < 0)
98 | return;
99 | LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) footerViewContanier.getLayoutParams();
100 | lp.height = deltaY;
101 | footerViewContanier.setLayoutParams(lp);
102 | }
103 |
104 | @Override
105 | public void footerViewShow() {
106 | LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) footerViewContanier.getLayoutParams();
107 | lp.height = LinearLayout.LayoutParams.WRAP_CONTENT;
108 | footerViewContanier.setLayoutParams(lp);
109 | }
110 |
111 | @Override
112 | public void footerViewHide() {
113 | LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) footerViewContanier.getLayoutParams();
114 | lp.height = 0;
115 | footerViewContanier.setLayoutParams(lp);
116 | }
117 |
118 | @Override
119 | public int getRealHeaderContentHeight() {
120 | if (mContentView != null) {
121 | return mContentView.getHeight();
122 | }
123 | return 0;
124 | }
125 | }
126 |
--------------------------------------------------------------------------------
/DragableRecyclerViewLib/src/main/java/com/zhl/dragablerecyclerview/view/CBRefreshHeader.java:
--------------------------------------------------------------------------------
1 | package com.zhl.dragablerecyclerview.view;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 | import android.view.Gravity;
6 | import android.view.LayoutInflater;
7 | import android.view.View;
8 | import android.view.animation.Animation;
9 | import android.view.animation.RotateAnimation;
10 | import android.widget.ImageView;
11 | import android.widget.LinearLayout;
12 | import android.widget.ProgressBar;
13 | import android.widget.RelativeLayout;
14 | import android.widget.TextView;
15 |
16 | import com.zhl.dragablerecyclerview.R;
17 | import com.zhl.dragablerecyclerview.titanic.Titanic;
18 | import com.zhl.dragablerecyclerview.titanic.TitanicTextView;
19 |
20 |
21 | public class CBRefreshHeader extends CBRefreshHeaderView {
22 | private LinearLayout mContainer;
23 | private RelativeLayout mHeaderViewContent;
24 | private ImageView mArrowImageView;
25 | private ProgressBar mProgressBar;
26 | private TextView mHintTextView;
27 | private TextView mHeaderTimeView;
28 | // the curent state
29 | private int mState = STATE_PULL_TO_REFRESH;
30 | private Animation mRotateUpAnim;
31 | private Animation mRotateDownAnim;
32 | private final int ROTATE_ANIM_DURATION = 200;
33 | private TitanicTextView headrAnimView;
34 | private Titanic titanic;
35 |
36 |
37 | public CBRefreshHeader(Context context) {
38 | this(context, null);
39 | }
40 |
41 | /**
42 | * @param context
43 | * @param attrs
44 | */
45 | public CBRefreshHeader(Context context, AttributeSet attrs) {
46 | super(context, attrs);
47 | initView(context);
48 | }
49 |
50 | private void initView(Context context) {
51 | // in the first set the Header height=0
52 | LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, 0);
53 | mContainer = (LinearLayout) LayoutInflater.from(context).inflate(R.layout.cblistview_header, null);
54 | mHeaderViewContent = (RelativeLayout) mContainer.findViewById(R.id.cbrefresh_header_content);
55 | mHeaderTimeView = (TextView) mContainer.findViewById(R.id.cbrefresh_header_time);
56 | addView(mContainer, lp);
57 | setGravity(Gravity.BOTTOM);
58 |
59 | mArrowImageView = (ImageView) findViewById(R.id.cbrefresh_header_arrow);
60 | mHintTextView = (TextView) findViewById(R.id.cbrefresh_header_hint_textview);
61 | mProgressBar = (ProgressBar) findViewById(R.id.cbrefresh_header_progressbar);
62 | headrAnimView = (TitanicTextView) findViewById(R.id.cbrefresh_header_anim);
63 | titanic = new Titanic();
64 | mRotateUpAnim = new RotateAnimation(0.0f, -180.0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
65 | mRotateUpAnim.setDuration(ROTATE_ANIM_DURATION);
66 | mRotateUpAnim.setFillAfter(true);
67 | mRotateDownAnim = new RotateAnimation(-180.0f, 0.0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
68 | mRotateDownAnim.setDuration(ROTATE_ANIM_DURATION);
69 | mRotateDownAnim.setFillAfter(true);
70 | }
71 |
72 | @Override
73 | public void setState(int state) {
74 | this.mState = state;
75 | }
76 |
77 | @Override
78 | public int getState() {
79 | return mState;
80 | }
81 |
82 | /**
83 | * @param resName
84 | */
85 | @Override
86 | public void setHeaderIcon(int resName) {
87 | mArrowImageView.setBackgroundResource(resName);
88 | }
89 |
90 | /**
91 | * set the footer bg
92 | *
93 | * @param resName
94 | */
95 | public void setHeaderBg(int resName) {
96 | this.setBackgroundResource(resName);
97 | }
98 |
99 | @Override
100 | public void pullToRefresh() {
101 | mHintTextView.setText(getString(R.string.refresh_header_tip_pull2refresh));
102 | mArrowImageView.setVisibility(View.VISIBLE);
103 | mProgressBar.setVisibility(View.INVISIBLE);
104 | if (mState == STATE_RELEASE_TO_REFRESH) {
105 | mArrowImageView.startAnimation(mRotateDownAnim);
106 | }
107 | if (mState == STATE_REFRESHING) {
108 | mArrowImageView.clearAnimation();
109 | }
110 | }
111 |
112 | @Override
113 | public void releaseToRefresh() {
114 | mHintTextView.setText(getString(R.string.refresh_header_tip_release2refresh));
115 | if (mState != STATE_RELEASE_TO_REFRESH) {
116 | mArrowImageView.clearAnimation();
117 | mArrowImageView.startAnimation(mRotateUpAnim);
118 | }
119 | }
120 |
121 | @Override
122 | public void onRefreshing() {
123 | mHintTextView.setText(getString(R.string.refresh_header_tip_refreshing));
124 | mArrowImageView.clearAnimation();
125 | mArrowImageView.setVisibility(View.INVISIBLE);
126 | mProgressBar.setVisibility(View.VISIBLE);
127 | }
128 |
129 | @Override
130 | public void onStyleChange(int state) {
131 | super.onStyleChange(state);
132 | }
133 |
134 | @Override
135 | public void setVisiableHeight(int height) {
136 | if (height < 0)
137 | height = 0;
138 | LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) mContainer.getLayoutParams();
139 | lp.height = height;
140 | mContainer.setLayoutParams(lp);
141 | }
142 |
143 | @Override
144 | public int getVisiableHeight() {
145 | return mContainer.getHeight();
146 | }
147 |
148 | @Override
149 | public int getRealHeaderContentHeight() {
150 | // beacuse container height =0 at the first ,so return mHeaderViewContent height
151 | if (mHeaderViewContent != null) {
152 | return mHeaderViewContent.getHeight();
153 | }
154 | return 0;
155 | }
156 |
157 | @Override
158 | public void setPullRefreshEnable(boolean enable) {
159 | if (!enable) { // disable, hide the content
160 | mHeaderViewContent.setVisibility(View.INVISIBLE);
161 | } else {
162 | mHeaderViewContent.setVisibility(View.VISIBLE);
163 | }
164 | }
165 |
166 | @Override
167 | public void setRefreshTime(String refreshTime) {
168 | mHeaderTimeView.setText(refreshTime);
169 | }
170 |
171 | @Override
172 | public void showHeaderAnim() {
173 | headrAnimView.setVisibility(VISIBLE);
174 | titanic.start(headrAnimView);
175 | }
176 |
177 | @Override
178 | public void stopHeaderAnim() {
179 | titanic.cancel();
180 | headrAnimView.setVisibility(GONE);
181 | }
182 | }
--------------------------------------------------------------------------------
/DragableRecyclerViewLib/src/main/java/com/zhl/dragablerecyclerview/view/CBRefreshHeaderView.java:
--------------------------------------------------------------------------------
1 | package com.zhl.dragablerecyclerview.view;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 | import android.widget.LinearLayout;
6 |
7 | public class CBRefreshHeaderView extends LinearLayout implements CBRefreshState {
8 | private Context context;
9 | public CBRefreshHeaderView(Context context) {
10 | this(context, null);
11 | }
12 |
13 | public CBRefreshHeaderView(Context context, AttributeSet attrs) {
14 | this(context, attrs, -1);
15 | }
16 |
17 | public CBRefreshHeaderView(Context context, AttributeSet attrs,
18 | int defStyleAttr) {
19 | super(context, attrs, defStyleAttr);
20 | this.context = context;
21 | }
22 |
23 | /**
24 | * set the current state
25 | * @param state
26 | */
27 | @Override
28 | public void setState(int state) {
29 |
30 | }
31 |
32 | @Override
33 | public int getState() {
34 | return 0;
35 | }
36 |
37 | /**
38 | * pull to refresh listener
39 | */
40 | @Override
41 | public void pullToRefresh() {
42 |
43 | }
44 |
45 | /**
46 | * relase to fresh listener
47 | */
48 | @Override
49 | public void releaseToRefresh() {
50 |
51 | }
52 |
53 |
54 | /**
55 | * pull up to loadmore
56 | */
57 | @Override
58 | public void pullUpToLoadmore() {
59 |
60 | }
61 |
62 | /**
63 | * relase to loadmore
64 | */
65 | @Override
66 | public void releaseToLoadmore() {
67 |
68 | }
69 |
70 | /**
71 | * onrefreshing
72 | */
73 | @Override
74 | public void onRefreshing() {
75 |
76 | }
77 |
78 | /**
79 | * onloading
80 | */
81 | @Override
82 | public void onLoading() {
83 |
84 | }
85 |
86 | /**
87 | * set the header height
88 | * @param height
89 | */
90 | @Override
91 | public void setVisiableHeight(int height) {
92 |
93 | }
94 |
95 | /**
96 | * get the header visiable height
97 | * @return
98 | */
99 | @Override
100 | public int getVisiableHeight() {
101 | return 0;
102 | }
103 |
104 | /**
105 | * on draging
106 | * @param deltaY
107 | */
108 | @Override
109 | public void onDragSlide(float deltaY) {
110 |
111 | }
112 | /**
113 | * get the pull up(footer) height
114 | */
115 | @Override
116 | public int getLoadMorePullUpDistance() {
117 | return 0;
118 | }
119 | /**
120 | * set the pull up(footer) heith
121 | */
122 | @Override
123 | public void setLoadMorePullUpDistance(int deltaY) {
124 |
125 | }
126 | /**
127 | * show footerview
128 | */
129 | @Override
130 | public void footerViewShow() {
131 |
132 | }
133 | /**
134 | * hidden footer view
135 | */
136 | @Override
137 | public void footerViewHide() {
138 |
139 | }
140 | /**
141 | * get the header's real height
142 | */
143 | @Override
144 | public int getRealHeaderContentHeight() {
145 | return 0;
146 | }
147 | /**
148 | * set pull refresh enable
149 | */
150 | @Override
151 | public void setPullRefreshEnable(boolean enable) {
152 |
153 | }
154 | /**
155 | * set loadmore enable
156 | */
157 | @Override
158 | public void setLoadMoreEnable(boolean enable) {
159 |
160 | }
161 |
162 | /**
163 | * set the refresh time
164 | * @param refreshTime
165 | */
166 | @Override
167 | public void setRefreshTime(String refreshTime) {
168 |
169 | }
170 |
171 | /**
172 | * set the header icon
173 | * @param resId
174 | */
175 | @Override
176 | public void setHeaderIcon(int resId) {
177 |
178 | }
179 |
180 | /**
181 | * on style change
182 | * @param state
183 | */
184 | @Override
185 | public void onStyleChange(int state) {
186 |
187 | }
188 |
189 | @Override
190 | public void showHeaderAnim() {
191 |
192 | }
193 |
194 | @Override
195 | public void stopHeaderAnim() {
196 |
197 | }
198 |
199 | protected String getString(int redID){
200 | return context.getString(redID);
201 | }
202 |
203 |
204 | }
205 |
--------------------------------------------------------------------------------
/DragableRecyclerViewLib/src/main/java/com/zhl/dragablerecyclerview/view/CBRefreshState.java:
--------------------------------------------------------------------------------
1 | package com.zhl.dragablerecyclerview.view;
2 |
3 | /**
4 | * 描述:刷新状态的接口
5 | * Created by zhaohl on 2016-3-22.
6 | */
7 | public interface CBRefreshState {
8 | /**
9 | * state pull to refresh
10 | */
11 | public final static int STATE_PULL_TO_REFRESH = 0;
12 | /**
13 | * state relase to refresh
14 | */
15 | public final static int STATE_RELEASE_TO_REFRESH = 1;
16 | /**
17 | * state on refreshing
18 | */
19 | public final static int STATE_REFRESHING = 2;
20 | /**
21 | * state pull to loadmore
22 | */
23 | public final static int STATE_PULL_UP_TO_LOADMORE = 3;
24 | /**
25 | * state relase to loadmore
26 | */
27 | public final static int STATE_RELEASE_TO_LOADMORE = 4;
28 |
29 | /**
30 | * set the state
31 | */
32 | public void setState(int state);
33 | public int getState();
34 | public void pullToRefresh();
35 |
36 | public void releaseToRefresh();
37 |
38 | public void pullUpToLoadmore();
39 |
40 | public void releaseToLoadmore();
41 |
42 | public void onRefreshing();
43 |
44 | public void onLoading();
45 |
46 | public void setVisiableHeight(int height);
47 |
48 | public int getVisiableHeight();
49 |
50 | public void onDragSlide(float deltaY);
51 |
52 | public int getLoadMorePullUpDistance();
53 |
54 | public void setLoadMorePullUpDistance(int deltaY);
55 |
56 | public void footerViewShow();
57 |
58 | public void footerViewHide();
59 |
60 | public int getRealHeaderContentHeight();
61 |
62 | public void setPullRefreshEnable(boolean enable);
63 |
64 | public void setLoadMoreEnable(boolean enable);
65 |
66 | public void setRefreshTime(String refreshTime);
67 |
68 | public void setHeaderIcon(int resId);
69 |
70 | public void onStyleChange(int state);
71 | public void showHeaderAnim();
72 | public void stopHeaderAnim();
73 | }
74 |
--------------------------------------------------------------------------------
/DragableRecyclerViewLib/src/main/java/com/zhl/dragablerecyclerview/view/DragableRecyclerView.java:
--------------------------------------------------------------------------------
1 | package com.zhl.dragablerecyclerview.view;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.content.Context;
5 | import android.graphics.Canvas;
6 | import android.graphics.Rect;
7 | import android.os.Build;
8 | import android.support.annotation.Nullable;
9 | import android.support.v4.view.GestureDetectorCompat;
10 | import android.support.v4.view.ViewCompat;
11 | import android.support.v7.widget.GridLayoutManager;
12 | import android.support.v7.widget.LinearLayoutManager;
13 | import android.support.v7.widget.RecyclerView;
14 | import android.support.v7.widget.StaggeredGridLayoutManager;
15 | import android.support.v7.widget.helper.ItemTouchHelper;
16 | import android.util.AttributeSet;
17 | import android.util.Log;
18 | import android.view.GestureDetector;
19 | import android.view.MotionEvent;
20 | import android.view.View;
21 | import android.view.ViewConfiguration;
22 | import android.view.ViewGroup;
23 | import android.view.ViewTreeObserver;
24 | import android.view.animation.DecelerateInterpolator;
25 | import android.widget.LinearLayout;
26 | import android.widget.Scroller;
27 |
28 | import com.zhl.dragablerecyclerview.swipemenu.SwipeMenu;
29 | import com.zhl.dragablerecyclerview.swipemenu.SwipeMenuAdapter;
30 | import com.zhl.dragablerecyclerview.swipemenu.SwipeMenuCreator;
31 | import com.zhl.dragablerecyclerview.swipemenu.SwipeMenuLayout;
32 | import com.zhl.dragablerecyclerview.swipemenu.SwipeMenuView;
33 | import com.zhl.dragablerecyclerview.utils.Utils;
34 |
35 | import java.text.SimpleDateFormat;
36 | import java.util.Date;
37 |
38 |
39 | /**
40 | * 描述:可拖拽排序,侧滑删除,下拉刷新上拉加载的recyclerview
41 | * Created by zhaohl on 2017-7-27.
42 | */
43 |
44 | public class DragableRecyclerView extends RecyclerView {
45 | private static final int TOUCH_STATE_NONE = 0;
46 | private static final int TOUCH_STATE_X = 1;
47 | private static final int TOUCH_STATE_Y = 2;
48 | private int mTouchPosition;
49 | private int mTouchState = TOUCH_STATE_NONE;
50 | private float mDownX;
51 | private float mDownY;
52 | private float disX, disY;
53 | private ItemTouchHelper itemTouchHelper;
54 | private SwipeMenuCreator mMenuCreator;
55 | private GestureDetectorCompat mGestureDetector;
56 | private GestureDetector.OnGestureListener mGestureListener;
57 | private float mLastY = -1;
58 | private boolean swipeEnable = false;
59 | private boolean swipeFlag = false;
60 | private SwipeMenuLayout mTouchView;
61 | private boolean isFling;
62 | private int MIN_FLING;
63 | private int MAX_VELOCITYX;
64 | private int touchSlop;
65 | private boolean isLongPressDragEnabled;
66 | private boolean longpressDragFlag;
67 | private OnItemDragListener onItemDragListener;
68 | private OnSwipedMenuItemClickListener onSwipedMenuItemClickListener;
69 | private OnItemClickListener onItemClickListener;
70 | private OnPullRefreshListener mPullRefreshListener;
71 | private SwipeMenuAdapter mWrapAdapter;
72 | private final RecyclerView.AdapterDataObserver mDataObserver = new DataObserver();
73 | // -- header view
74 | private CBRefreshHeaderView mHeaderView;
75 | // -- footer view
76 | private CBRefreshHeaderView mFooterView;
77 | private int mHeaderViewHeight; // header view's height
78 | private int mFooterViewHeight; // header view's height
79 | private boolean mEnablePullRefresh = true;
80 | private boolean mPullRefreshing = false; // is refreashing.
81 | private boolean mEnablePullLoad;
82 | private boolean mPullLoading;// isLoading
83 | // private boolean mIsFooterReady = false;
84 | // total list items, used to detect is at the bottom of listview.
85 | // private int mTotalItemCount = 0;
86 | // for mScroller, scroll back from header or footer.
87 | private int mScrollBack;
88 | private final static int SCROLLBACK_HEADER = 0;
89 | private final static int SCROLLBACK_FOOTER = 1;
90 | private final static int SCROLL_DURATION = 300; // scroll back duration
91 | // private final static int PULL_LOAD_MORE_DELTA = 150; // when pull up >= 150px
92 | private final static float OFFSET_RADIO = 2.3f; // support iOS like pull
93 | // feature.
94 | // private boolean showTopSearchBar = false;
95 | // private CBRefreshHeaderView topSearchView;
96 | // private int topSearchBarHeight = 0;
97 | private Scroller mScroller;
98 | private long refreshTime;
99 | private LinearLayout.LayoutParams headerParams;
100 |
101 | public DragableRecyclerView(Context context) {
102 | this(context, null);
103 | }
104 |
105 | public DragableRecyclerView(Context context, @Nullable AttributeSet attrs) {
106 | this(context, attrs, -1);
107 | }
108 |
109 | public DragableRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
110 | super(context, attrs, defStyle);
111 | init(context);
112 | }
113 |
114 | private void init(Context context) {
115 | touchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
116 | MIN_FLING = ViewConfiguration.get(context).getScaledMinimumFlingVelocity();
117 | MAX_VELOCITYX = ViewConfiguration.get(context).getScaledMaximumFlingVelocity();
118 | headerParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
119 | mHeaderView = new CBRefreshHeader(context);
120 | mHeaderView.setLayoutParams(headerParams);
121 | // init footer view
122 | mFooterView = new CBRefreshFooter(context);
123 | mFooterView.setLayoutParams(headerParams);
124 | initHeaderHeight();
125 | // headerview and footer divider
126 | itemTouchHelper = new ItemTouchHelper(new ItemTouchHelper.Callback() {
127 | @Override
128 | public boolean isItemViewSwipeEnabled() {
129 | return false;
130 | }
131 |
132 | @Override
133 | public boolean isLongPressDragEnabled() {
134 | return isLongPressDragEnabled;
135 | }
136 |
137 | @Override
138 | public int getMovementFlags(RecyclerView recyclerView, ViewHolder viewHolder) {
139 | int dragFlag = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
140 | int swipeFlag = ItemTouchHelper.LEFT;
141 | LayoutManager layoutmanager = getLayoutManager();
142 | if (layoutmanager != null && (layoutmanager instanceof GridLayoutManager || layoutmanager instanceof StaggeredGridLayoutManager)) {
143 | dragFlag = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
144 | }
145 | return makeMovementFlags(dragFlag, swipeFlag);
146 | }
147 |
148 | @Override
149 | public boolean onMove(RecyclerView recyclerView, ViewHolder viewHolder, ViewHolder target) {
150 | int from = viewHolder.getAdapterPosition();
151 | int to = target.getAdapterPosition();
152 | if (mEnablePullRefresh && to == 0) {
153 | return false;
154 | }
155 | if (mEnablePullLoad && to == recyclerView.getAdapter().getItemCount() - 1) {
156 | return false;
157 | }
158 | getAdapter().notifyItemMoved(from, to);
159 | return true;
160 | }
161 |
162 | @Override
163 | public void onMoved(RecyclerView recyclerView, ViewHolder viewHolder, int fromPos, ViewHolder target, int toPos, int x, int y) {
164 | super.onMoved(recyclerView, viewHolder, fromPos, target, toPos, x, y);
165 | if (onItemDragListener != null) {
166 | onItemDragListener.onMoved(recyclerView, ((SwipeMenuAdapter.SwipeMenuViewHolder) viewHolder).getOrignalHolder(), fromPos, target, toPos, x, y);
167 | }
168 | }
169 |
170 | @Override
171 | public void onSwiped(ViewHolder viewHolder, int direction) {
172 | // int removedPos = viewHolder.getAdapterPosition();
173 | // getAdapter().notifyItemRemoved(removedPos);
174 | // if (null!=onItemDragListener) {
175 | // onItemDragListener.onSwiped(viewHolder,direction);
176 | // }
177 | }
178 |
179 | @Override
180 | public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
181 | super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
182 | }
183 |
184 | @Override
185 | public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
186 | if (isLongPressDragEnabled) {
187 | swipeEnable = false;
188 | }
189 | super.onSelectedChanged(viewHolder, actionState);
190 | if (null != onItemDragListener && onItemDragListener.onDragScaleable() && actionState == ItemTouchHelper.ACTION_STATE_DRAG) {
191 | ViewCompat.setScaleX(viewHolder.itemView, 1.1f);
192 | ViewCompat.setScaleY(viewHolder.itemView, 1.1f);
193 | }
194 | if (null != onItemDragListener && viewHolder != null) {
195 | onItemDragListener.onSelectedChanged(((SwipeMenuAdapter.SwipeMenuViewHolder) viewHolder).getOrignalHolder(), actionState);
196 | }
197 | }
198 |
199 | @Override
200 | public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
201 | super.clearView(recyclerView, viewHolder);
202 | ViewCompat.setScaleX(viewHolder.itemView, 1.0f);
203 | ViewCompat.setScaleY(viewHolder.itemView, 1.0f);
204 | if (swipeFlag) {
205 | swipeEnable = true;
206 | }
207 | if (null != onItemDragListener) {
208 | onItemDragListener.onDragCompleted(recyclerView, ((SwipeMenuAdapter.SwipeMenuViewHolder) viewHolder).getOrignalHolder());
209 | }
210 | }
211 | });
212 | itemTouchHelper.attachToRecyclerView(this);
213 | mGestureListener = new GestureDetector.SimpleOnGestureListener() {
214 | @Override
215 | public boolean onDown(MotionEvent e) {
216 | isFling = false;
217 | return true;
218 | }
219 |
220 | @Override
221 | public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
222 | if (e1 == null) {
223 | return false;
224 | }
225 | if ((e1.getX() - e2.getX()) > MIN_FLING && velocityX < MAX_VELOCITYX) {
226 | isFling = true;
227 | }
228 | return super.onFling(e1, e2, velocityX, velocityY);
229 | }
230 | };
231 | mGestureDetector = new GestureDetectorCompat(getContext(), mGestureListener);
232 | mScroller = new Scroller(context, new DecelerateInterpolator());
233 | }
234 |
235 | private void initHeaderHeight() {
236 | mHeaderView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
237 | @Override
238 | public void onGlobalLayout() {
239 | mHeaderViewHeight = mHeaderView.getRealHeaderContentHeight();
240 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
241 | getViewTreeObserver().removeOnGlobalLayoutListener(this);
242 | } else {
243 | getViewTreeObserver().removeGlobalOnLayoutListener(this);
244 | }
245 | }
246 | });
247 | mFooterView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
248 | @Override
249 | public void onGlobalLayout() {
250 | mFooterViewHeight = mFooterView.getRealHeaderContentHeight();
251 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
252 | getViewTreeObserver().removeOnGlobalLayoutListener(this);
253 | } else {
254 | getViewTreeObserver().removeGlobalOnLayoutListener(this);
255 | }
256 | }
257 | });
258 | }
259 |
260 | /**
261 | * 设置侧滑菜单构造器
262 | *
263 | * @param menuCreator
264 | */
265 | public void setMenuCreator(SwipeMenuCreator menuCreator) {
266 | this.mMenuCreator = menuCreator;
267 | }
268 |
269 | @Override
270 | public void setAdapter(Adapter adapter) {
271 | super.setAdapter(mWrapAdapter = new SwipeMenuAdapter(getContext(), adapter) {
272 | @Override
273 | protected void createMenu(SwipeMenu menu) {
274 | if (mMenuCreator != null) {
275 | mMenuCreator.create(menu);
276 | }
277 | }
278 |
279 | @Override
280 | protected boolean isPullRefreshEnable() {
281 | return mEnablePullRefresh;
282 | }
283 |
284 | @Override
285 | protected boolean isPullLoadMoreEnable() {
286 | return mEnablePullLoad;
287 | }
288 |
289 | @Override
290 | protected View getHeaderView() {
291 | return mHeaderView;
292 | }
293 |
294 | @Override
295 | protected View getFooterView() {
296 | return mFooterView;
297 | }
298 |
299 | @Override
300 | public void onItemClick(SwipeMenuView view, SwipeMenu menu, int index) {
301 | if (mTouchView != null) {
302 | mTouchView.smoothCloseMenu();
303 | }
304 | if (null != onSwipedMenuItemClickListener) {
305 | onSwipedMenuItemClickListener.onMenuItemClick(mTouchPosition, getAdapter(), menu, index);
306 | }
307 | }
308 | });
309 | adapter.registerAdapterDataObserver(mDataObserver);
310 | mDataObserver.onChanged();
311 | }
312 |
313 | private class DataObserver extends RecyclerView.AdapterDataObserver {
314 | @Override
315 | public void onChanged() {
316 | if (mWrapAdapter != null) {
317 | mWrapAdapter.notifyDataSetChanged();
318 | }
319 | }
320 |
321 | @Override
322 | public void onItemRangeInserted(int positionStart, int itemCount) {
323 | mWrapAdapter.notifyItemRangeInserted(positionStart, itemCount);
324 | }
325 |
326 | @Override
327 | public void onItemRangeChanged(int positionStart, int itemCount) {
328 | mWrapAdapter.notifyItemRangeChanged(positionStart, itemCount);
329 | }
330 |
331 | @Override
332 | public void onItemRangeChanged(int positionStart, int itemCount, Object payload) {
333 | mWrapAdapter.notifyItemRangeChanged(positionStart, itemCount, payload);
334 | }
335 |
336 | @Override
337 | public void onItemRangeRemoved(int positionStart, int itemCount) {
338 | mWrapAdapter.notifyItemRangeRemoved(positionStart, itemCount);
339 | }
340 |
341 | @Override
342 | public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
343 | mWrapAdapter.notifyItemMoved(fromPosition, toPosition);
344 | }
345 | }
346 |
347 | @Override
348 | public boolean onTouchEvent(MotionEvent ev) {
349 | mGestureDetector.onTouchEvent(ev);
350 | if (mLastY == -1) {
351 | mLastY = ev.getRawY();
352 | }
353 |
354 | switch (ev.getAction()) {
355 | case MotionEvent.ACTION_DOWN:
356 | mLastY = ev.getRawY();
357 | mDownX = ev.getX();
358 | mDownY = ev.getY();
359 | int oldPos = mTouchPosition;
360 | mTouchPosition = pointToPosition((int) ev.getX(), (int) ev.getY());
361 | View view = getChildAt(mTouchPosition - getFirstVisiblePosition());
362 | if (swipeEnable && mTouchView != null && (mTouchView.isOpen() || mTouchView.isActive()) && oldPos != mTouchPosition) {
363 | mTouchView.smoothCloseMenu();
364 | mTouchView = null;
365 | mTouchState = TOUCH_STATE_NONE;
366 | }
367 | if (view instanceof SwipeMenuLayout) {
368 | mTouchView = (SwipeMenuLayout) view;
369 | }
370 | break;
371 | case MotionEvent.ACTION_MOVE:
372 | final float deltaY = ev.getRawY() - mLastY;
373 | mLastY = ev.getRawY();
374 | disX = ev.getX() - mDownX;
375 | disY = ev.getY() - mDownY;
376 |
377 | if (Math.abs(disX) > touchSlop && Math.abs(disX) > Math.abs(disY)) {// 左右滑动
378 | mTouchState = TOUCH_STATE_X;
379 | if (swipeEnable && mTouchView != null) {
380 | if (longpressDragFlag) {
381 | isLongPressDragEnabled = false;
382 | }
383 | mTouchView.swipeMenuSlide(-(int) disX);
384 | if (mTouchView.isActive()) {
385 | return true;
386 | }
387 | }
388 | } else if (Math.abs(disY) > touchSlop && Math.abs(disY) > Math.abs(disX)) {// 上下滑动
389 | if ((swipeEnable && mTouchView != null && mTouchView.isOpen()) || (swipeEnable && mTouchView != null && mTouchView.isActive())) {
390 | mTouchView.smoothCloseMenu();
391 | mTouchView = null;
392 | mTouchState = TOUCH_STATE_NONE;
393 | }
394 | mTouchState = TOUCH_STATE_Y;
395 | if (mEnablePullRefresh && getFirstVisiblePosition() <= 1 && (mHeaderView.getVisiableHeight() > 0 || deltaY > 0)) {// 下拉
396 | updateHeaderHeight(deltaY / OFFSET_RADIO);
397 | mHeaderView.onDragSlide((float) mHeaderView.getVisiableHeight() + Math.abs(deltaY / OFFSET_RADIO));
398 | invokeOnScrolling();
399 |
400 | } else if (mEnablePullLoad && getLastVisiblePosition() >= getAdapter().getItemCount() - 2 && (mFooterView.getLoadMorePullUpDistance() > 0 || deltaY < 0)) {// 上拉
401 | updateFooterHeight(-deltaY / OFFSET_RADIO);
402 | mFooterView.onDragSlide((float) mFooterView.getLoadMorePullUpDistance() + (-deltaY / OFFSET_RADIO));
403 | }
404 | }
405 | break;
406 | default:
407 | mLastY = -1; // reset
408 | switch (mTouchState) {
409 | case TOUCH_STATE_X:
410 | if (swipeEnable && mTouchView != null) {
411 | mTouchView.swipeMenuFling(isFling, -(int) disX);
412 | if (mTouchView.isActive()) {
413 | return true;
414 | }
415 | }
416 | break;
417 | case TOUCH_STATE_Y:
418 | if (getFirstVisiblePosition() == 0) {
419 | // invoke refresh
420 | if (mEnablePullRefresh && mHeaderView.getVisiableHeight() > mHeaderViewHeight) {
421 | mPullRefreshing = true;
422 | mHeaderView.onRefreshing();
423 | mHeaderView.setState(CBRefreshState.STATE_REFRESHING);
424 | if (mPullRefreshListener != null) {
425 | mPullRefreshListener.onRefresh();
426 | mPullRefreshListener.onUpdateRefreshTime(System.currentTimeMillis());
427 | }
428 | setRefreshTime(System.currentTimeMillis());
429 | }
430 | resetHeaderHeight();
431 | } else if (getLastVisiblePosition() == getAdapter().getItemCount() - 1) {
432 | // invoke load more.
433 | if (mEnablePullLoad && mFooterView.getLoadMorePullUpDistance() > mFooterViewHeight) {
434 | startLoadMore();
435 | }
436 | resetFooterHeight();
437 | } else {
438 | if (mHeaderView.getVisiableHeight() > 0 || disY > 0) {
439 | resetHeaderHeight();
440 | }
441 | }
442 | break;
443 | case TOUCH_STATE_NONE:
444 | if (onItemClickListener != null) {
445 | int clickPos = mEnablePullRefresh ? getFirstVisiblePosition() == 1 ? mTouchPosition - 2 : mTouchPosition - 1 : mTouchPosition;
446 | if (clickPos >= 0) {
447 | onItemClickListener.onItemClick(clickPos, getAdapter(), mTouchView);
448 | }
449 | }
450 | break;
451 | }
452 | mTouchState = TOUCH_STATE_NONE;
453 | if (longpressDragFlag) {
454 | isLongPressDragEnabled = true;
455 | }
456 | break;
457 | }
458 | return super.onTouchEvent(ev);
459 | }
460 |
461 |
462 | private int getFirstVisiblePosition() {
463 | LayoutManager layoutManager = getLayoutManager();
464 | if (layoutManager instanceof LinearLayoutManager) {
465 | return ((LinearLayoutManager) layoutManager).findFirstVisibleItemPosition();
466 | } else if (layoutManager instanceof GridLayoutManager) {
467 | return ((GridLayoutManager) layoutManager).findFirstVisibleItemPosition();
468 | } else if (layoutManager instanceof StaggeredGridLayoutManager) {
469 | int[] span = new int[((StaggeredGridLayoutManager) layoutManager).getSpanCount()];
470 | ((StaggeredGridLayoutManager) layoutManager).findFirstVisibleItemPositions(span);
471 | return findMin(span);
472 | }
473 | return 0;
474 | }
475 |
476 | private int findMax(int[] lastPositions) {
477 | int max = lastPositions[0];
478 | for (int value : lastPositions) {
479 | if (value > max) {
480 | max = value;
481 | }
482 | }
483 | return max;
484 | }
485 |
486 | private int findMin(int[] lastPositions) {
487 | int min = lastPositions[0];
488 | for (int value : lastPositions) {
489 | if (value < min) {
490 | min = value;
491 | }
492 | }
493 | return min;
494 | }
495 |
496 | private int getLastVisiblePosition() {
497 | LayoutManager layoutManager = getLayoutManager();
498 | if (layoutManager instanceof LinearLayoutManager) {
499 | return ((LinearLayoutManager) layoutManager).findLastVisibleItemPosition();
500 | } else if (layoutManager instanceof GridLayoutManager) {
501 | return ((GridLayoutManager) layoutManager).findLastVisibleItemPosition();
502 | } else if (layoutManager instanceof StaggeredGridLayoutManager) {
503 | int[] span = new int[((StaggeredGridLayoutManager) layoutManager).getSpanCount()];
504 | ((StaggeredGridLayoutManager) layoutManager).findLastVisibleItemPositions(span);
505 | return findMax(span);
506 | }
507 | return 0;
508 | }
509 |
510 | private int pointToPosition(int x, int y) {
511 | final int count = getChildCount();
512 | Rect frame = new Rect();
513 | int pos = 0;
514 | for (int i = count - 1; i >= 0; i--) {
515 | final View child = getChildAt(i);
516 | if (child.getVisibility() == View.VISIBLE) {
517 | child.getHitRect(frame);
518 | if (frame.contains(x, y)) {
519 | pos = getFirstVisiblePosition() + i;
520 | }
521 | }
522 | }
523 | return pos;
524 | }
525 |
526 | private void startLoadMore() {
527 | mPullLoading = true;
528 | mFooterView.onLoading();
529 | mFooterView.setState(CBRefreshState.STATE_REFRESHING);
530 | if (mPullRefreshListener != null) {
531 | mPullRefreshListener.onLoadMore();
532 | }
533 | }
534 |
535 | private void updateHeaderHeight(float delta) {
536 | mHeaderView.setVisiableHeight((int) delta + mHeaderView.getVisiableHeight());
537 | if (mEnablePullRefresh && !mPullRefreshing) {
538 | if (mHeaderView.getVisiableHeight() > mHeaderViewHeight) {
539 | mHeaderView.releaseToRefresh();
540 | mHeaderView.setState(CBRefreshState.STATE_RELEASE_TO_REFRESH);
541 | } else {
542 | mHeaderView.pullToRefresh();
543 | mHeaderView.setState(CBRefreshState.STATE_PULL_TO_REFRESH);
544 | }
545 | }
546 | }
547 |
548 | /**
549 | * 恢复刷新头高度
550 | */
551 | private void resetHeaderHeight() {
552 | int height = mHeaderView.getVisiableHeight();
553 | if (height == 0)
554 | return;
555 | // refreshing and header isn't shown fully. do nothing.
556 | if (mPullRefreshing && height <= mHeaderViewHeight) {
557 | return;
558 | }
559 | int finalHeight = 0; // default: scroll back to dismiss header.
560 | // is refreshing, just scroll back to show all the header.
561 | if (mPullRefreshing && height > mHeaderViewHeight) {
562 | finalHeight = mHeaderViewHeight;
563 | }
564 | mScrollBack = SCROLLBACK_HEADER;
565 | mScroller.startScroll(0, height, 0, finalHeight - height, SCROLL_DURATION);
566 | // trigger computeScroll
567 | invalidate();
568 | }
569 |
570 | /**
571 | * 更新下拉头高度
572 | *
573 | * @param delta
574 | */
575 | private void updateFooterHeight(float delta) {
576 | if (!mEnablePullLoad) {
577 | return;
578 | }
579 | int height = mFooterView.getLoadMorePullUpDistance() + (int) delta;
580 | Log.i("mytag", "footer height =" + height);
581 | if (mEnablePullLoad && !mPullLoading) {
582 | if (height > mFooterViewHeight) { // height enough to invoke load more.
583 | mFooterView.releaseToLoadmore();
584 | mFooterView.setState(CBRefreshState.STATE_RELEASE_TO_LOADMORE);
585 | } else {
586 | mFooterView.pullUpToLoadmore();
587 | mFooterView.setState(CBRefreshState.STATE_PULL_UP_TO_LOADMORE);
588 | }
589 | }
590 | mFooterView.setLoadMorePullUpDistance(height);
591 |
592 | // setSelection(mTotalItemCount - 1); // scroll to bottom
593 | }
594 |
595 | /**
596 | * 恢复下拉头高度
597 | */
598 | private void resetFooterHeight() {
599 | int footerHeight = mFooterView.getLoadMorePullUpDistance();
600 | if (footerHeight == 0) {
601 | return;
602 | }
603 | if (mPullLoading && footerHeight <= mFooterViewHeight) {
604 | return;
605 | }
606 |
607 | int finalHeight = 0;
608 | if (mPullLoading && footerHeight > mFooterViewHeight) {
609 | finalHeight = mFooterViewHeight;
610 | }
611 | mScrollBack = SCROLLBACK_FOOTER;
612 | mScroller.startScroll(0, footerHeight, 0, finalHeight - footerHeight, SCROLL_DURATION);
613 | invalidate();
614 |
615 | }
616 |
617 | @Override
618 | public void computeScroll() {
619 | if (mScroller.computeScrollOffset()) {
620 | if (mScrollBack == SCROLLBACK_HEADER) {
621 | mHeaderView.setVisiableHeight(mScroller.getCurrY());
622 | mHeaderView.onDragSlide(mScroller.getCurrY());
623 | } else {
624 | mFooterView.setLoadMorePullUpDistance(mScroller.getCurrY());
625 | mFooterView.onDragSlide(mScroller.getCurrY());
626 | }
627 | postInvalidate();
628 | invokeOnScrolling();
629 | }
630 | super.computeScroll();
631 | }
632 |
633 | /**
634 | * 是否开启下拉刷新
635 | *
636 | * @param enable
637 | */
638 | public void setPullRefreshEnable(boolean enable) {
639 | mEnablePullRefresh = enable;
640 | mHeaderView.setPullRefreshEnable(mEnablePullRefresh);
641 | }
642 |
643 | /**
644 | * 设置刷新头刷新图片
645 | *
646 | * @param resName
647 | */
648 | public void setHeaderRefreshIcon(int resName) {
649 | if (mHeaderView != null) {
650 | mHeaderView.setHeaderIcon(resName);
651 | }
652 | }
653 |
654 | /**
655 | * 设置刷新头背景
656 | *
657 | * @param resName
658 | */
659 | public void setHeaderBg(int resName) {
660 | if (mHeaderView != null) {
661 | ((CBRefreshHeader) mHeaderView).setHeaderBg(resName);
662 | }
663 | }
664 |
665 | /**
666 | * set footer view background
667 | *
668 | * @param resName
669 | */
670 | public void setFooterBg(int resName) {
671 | if (mFooterView != null) {
672 | ((CBRefreshFooter) mFooterView).setFooterBg(resName);
673 | }
674 | }
675 |
676 | /**
677 | * 可以需要换肤的情况下调用此方法(自己定义刷新头去实现相应的换肤操作)
678 | *
679 | * @param state
680 | */
681 | public void setStyleChange(int state) {
682 | mHeaderView.onStyleChange(state);
683 | mFooterView.onStyleChange(state);
684 | }
685 |
686 | /**
687 | * 是否开启上拉加载
688 | *
689 | * @param enable
690 | */
691 | public void setPullLoadMoreEnable(boolean enable) {
692 | mEnablePullLoad = enable;
693 | if (!mEnablePullLoad) {
694 | mFooterView.footerViewHide();
695 | mFooterView.setOnClickListener(null);
696 | } else {
697 | mPullLoading = false;
698 | mFooterView.footerViewShow();
699 | mFooterView.setState(CBRefreshState.STATE_PULL_UP_TO_LOADMORE);
700 | mFooterView.pullUpToLoadmore();
701 | mFooterView.setOnClickListener(new OnClickListener() {
702 | @Override
703 | public void onClick(View v) {
704 | startLoadMore();
705 | }
706 | });
707 | }
708 | }
709 |
710 | /**
711 | * 设置刷新头
712 | *
713 | * @param header
714 | * @param
715 | */
716 | public void setRefreshHeader(T header) {
717 | if (header == null) {
718 | return;
719 | }
720 | setPullRefreshEnable(true);
721 | if (mWrapAdapter != null) {
722 | mWrapAdapter.notifyItemRemoved(0);
723 | }
724 | mHeaderView = header;
725 | mHeaderView.setLayoutParams(headerParams);
726 | initHeaderHeight();
727 | if (mWrapAdapter != null) {
728 | mWrapAdapter.notifyItemInserted(0);
729 | }
730 | }
731 |
732 | /**
733 | * 设置加载更多的footerview
734 | *
735 | * @param footer
736 | * @param
737 | */
738 | public void setLoadMoreFooter(T footer) {
739 | if (footer == null) {
740 | return;
741 | }
742 | setPullLoadMoreEnable(true);
743 | if (mWrapAdapter != null) {
744 | mWrapAdapter.notifyItemRemoved(mWrapAdapter.getItemCount() - 1);
745 | }
746 | mFooterView = footer;
747 | mFooterView.setLayoutParams(headerParams);
748 | initHeaderHeight();
749 | if (mWrapAdapter != null) {
750 | mWrapAdapter.notifyItemInserted(mWrapAdapter.getItemCount() - 1);
751 | }
752 | }
753 |
754 | /**
755 | * 设置刷新时间
756 | *
757 | * @param time timestamp
758 | */
759 | public void setRefreshTime(long time) {
760 | if (time <= 0) {
761 | setRefreshTime(null);
762 | } else {
763 | refreshTime = time;
764 | setRefreshTime(Utils.getTimeDifferent(getContext(), time));
765 | }
766 | }
767 |
768 | /**
769 | * set last refresh time
770 | *
771 | * @param time
772 | */
773 | @SuppressLint("SimpleDateFormat")
774 | public void setRefreshTime(String time) {
775 | if (null == time) {
776 | Date now = new Date();
777 | SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
778 | mHeaderView.setRefreshTime(dateFormat.format(now));
779 | } else {
780 | mHeaderView.setRefreshTime(time);
781 | }
782 | }
783 |
784 | /**
785 | * 显示刷新头动画 对应的停止{@link #stopHeaderAnim()}
786 | */
787 | public void showHeaderAnim() {
788 | if (mEnablePullRefresh && mHeaderView != null) {
789 | mHeaderView.showHeaderAnim();
790 | }
791 | }
792 |
793 | /**
794 | * 停止刷新头动画 对应的开始{@link #showHeaderAnim()}
795 | */
796 | public void stopHeaderAnim() {
797 | if (mEnablePullRefresh && mHeaderView != null) {
798 | mHeaderView.stopHeaderAnim();
799 | }
800 | }
801 |
802 | /**
803 | * 停止刷新 恢复刷新头
804 | */
805 | public void stopRefresh() {
806 | if (mPullRefreshing == true) {
807 | mPullRefreshing = false;
808 | resetHeaderHeight();
809 | mHeaderView.setState(CBRefreshState.STATE_PULL_TO_REFRESH);
810 | }
811 | }
812 |
813 | /**
814 | * stop load more, reset footer view.
815 | */
816 | public void stopLoadMore() {
817 | if (mPullLoading == true) {
818 | mPullLoading = false;
819 | resetFooterHeight();
820 | mFooterView.pullUpToLoadmore();
821 | mFooterView.setState(CBRefreshState.STATE_PULL_UP_TO_LOADMORE);
822 | }
823 | }
824 |
825 | /**
826 | * 是否开启侧滑菜单
827 | *
828 | * @param swipeEnable
829 | */
830 | public void setSwipeEnable(boolean swipeEnable) {
831 | this.swipeEnable = swipeEnable;
832 | this.swipeFlag = swipeEnable;
833 | }
834 |
835 | /**
836 | * 是否开启长按拖拽
837 | *
838 | * @param longPressDragEnabled
839 | */
840 | public void setLongPressDragEnabled(boolean longPressDragEnabled) {
841 | this.isLongPressDragEnabled = longPressDragEnabled;
842 | this.longpressDragFlag = longPressDragEnabled;
843 | }
844 |
845 | /**
846 | * 设置长按拖拽监听
847 | *
848 | * @param onItemDragListener
849 | */
850 | public void setOnItemDragListener(OnItemDragListener onItemDragListener) {
851 | this.onItemDragListener = onItemDragListener;
852 | }
853 |
854 |
855 | /**
856 | * 长按拖拽监听
857 | */
858 | public interface OnItemDragListener {
859 | /**
860 | * 长按拖动view 发生改变
861 | *
862 | * @param viewHolder
863 | * @param actionState
864 | */
865 | public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState);
866 |
867 | /**
868 | * 移动交换一个位置调用
869 | *
870 | * @param recyclerView
871 | * @param viewHolder
872 | * @param fromPos
873 | * @param target
874 | * @param toPos
875 | * @param x
876 | * @param y
877 | */
878 | public void onMoved(RecyclerView recyclerView, ViewHolder viewHolder, int fromPos, ViewHolder target, int toPos, int x, int y);
879 |
880 | /**
881 | * 拖动view是否具有放大效果
882 | *
883 | * @return
884 | */
885 | public boolean onDragScaleable();
886 |
887 | /**
888 | * 拖拽完成
889 | *
890 | * @param recyclerView
891 | * @param viewHolder
892 | */
893 | public void onDragCompleted(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder);
894 | }
895 |
896 | /**
897 | * 设置侧滑菜单监听
898 | *
899 | * @param onSwipedMenuItemClickListener
900 | */
901 | public void setOnSwipedMenuItemClickListener(OnSwipedMenuItemClickListener onSwipedMenuItemClickListener) {
902 | this.onSwipedMenuItemClickListener = onSwipedMenuItemClickListener;
903 | }
904 |
905 | /**
906 | * 侧滑菜单点击监听回调
907 | */
908 | public interface OnSwipedMenuItemClickListener {
909 | /**
910 | * 侧滑菜单点击监听回调
911 | *
912 | * @param position recyclerview position
913 | * @param adapter recyclerview adapter
914 | * @param menu swipemenu
915 | * @param index swipemenu index 侧滑菜单索引
916 | */
917 | public void onMenuItemClick(int position, Adapter adapter, SwipeMenu menu, int index);
918 | }
919 |
920 | /**
921 | * 设置recycleview的onitem监听
922 | *
923 | * @param onItemClickListener
924 | */
925 | public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
926 | this.onItemClickListener = onItemClickListener;
927 | }
928 |
929 | /**
930 | * recyclerview的item点击事件监听回调
931 | */
932 | public interface OnItemClickListener {
933 | /**
934 | * recyclerview的item点击事件监听回调
935 | *
936 | * @param position
937 | * @param adapter
938 | * @param ConvertView
939 | */
940 | public void onItemClick(int position, Adapter adapter, View ConvertView);
941 | }
942 |
943 | private void invokeOnScrolling() {
944 | // if (mScrollListener instanceof OnXScrollListener) {
945 | // OnXScrollListener l = (OnXScrollListener) mScrollListener;
946 | // l.onXScrolling(this);
947 | // }
948 | }
949 |
950 | /**
951 | * 设置下拉刷新监听
952 | *
953 | * @param mPullRefreshListener
954 | */
955 | public void setPullRefreshListener(OnPullRefreshListener mPullRefreshListener) {
956 | this.mPullRefreshListener = mPullRefreshListener;
957 | }
958 |
959 | /**
960 | * the refresh listener
961 | */
962 | public interface OnPullRefreshListener {
963 | public void onRefresh();
964 |
965 | public void onLoadMore();
966 |
967 | public void onUpdateRefreshTime(long time);
968 | }
969 |
970 | }
971 |
--------------------------------------------------------------------------------
/DragableRecyclerViewLib/src/main/res/drawable-nodpi/wave.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yilylong/DragableRecyclerView/c392b85c03a8eee24d6809c99e4c39c0dd95d911/DragableRecyclerViewLib/src/main/res/drawable-nodpi/wave.png
--------------------------------------------------------------------------------
/DragableRecyclerViewLib/src/main/res/drawable-xhdpi/icon_header_refresh.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yilylong/DragableRecyclerView/c392b85c03a8eee24d6809c99e4c39c0dd95d911/DragableRecyclerViewLib/src/main/res/drawable-xhdpi/icon_header_refresh.png
--------------------------------------------------------------------------------
/DragableRecyclerViewLib/src/main/res/drawable-xhdpi/top_pull_refresh_arrow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yilylong/DragableRecyclerView/c392b85c03a8eee24d6809c99e4c39c0dd95d911/DragableRecyclerViewLib/src/main/res/drawable-xhdpi/top_pull_refresh_arrow.png
--------------------------------------------------------------------------------
/DragableRecyclerViewLib/src/main/res/drawable-xhdpi/top_search_bar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yilylong/DragableRecyclerView/c392b85c03a8eee24d6809c99e4c39c0dd95d911/DragableRecyclerViewLib/src/main/res/drawable-xhdpi/top_search_bar.png
--------------------------------------------------------------------------------
/DragableRecyclerViewLib/src/main/res/drawable/footer_bg_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/DragableRecyclerViewLib/src/main/res/layout/cblistview_footer.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
12 |
13 |
22 |
23 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/DragableRecyclerViewLib/src/main/res/layout/cblistview_header.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
11 |
12 |
26 |
27 |
35 |
36 |
44 |
45 |
49 |
50 |
57 |
58 |
64 |
65 |
66 |
67 |
75 |
76 |
85 |
86 |
87 |
--------------------------------------------------------------------------------
/DragableRecyclerViewLib/src/main/res/layout/cbpullrefrsh_topsearch.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
24 |
28 |
29 |
--------------------------------------------------------------------------------
/DragableRecyclerViewLib/src/main/res/layout/header.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
14 |
--------------------------------------------------------------------------------
/DragableRecyclerViewLib/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFFFFF
4 | #ECEDED
5 | #3fbecc
6 | #f1494c
7 | #efefef
8 | #f1f1f1
9 | #a6a7a6
10 |
--------------------------------------------------------------------------------
/DragableRecyclerViewLib/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
--------------------------------------------------------------------------------
/DragableRecyclerViewLib/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | PullRefreshLibrary
3 |
4 | Hello world!
5 | Settings
6 | 下拉刷新
7 | 松开刷新数据
8 | 正在刷新...
9 | 正在加载...
10 | 上拉加载更多
11 | 松开载入更多
12 | 小时前
13 | 刚刚
14 | 10分钟前
15 | 20分钟前
16 | 30分钟前
17 | yyyy年MM月dd日 HH时mm分ss秒
18 | MM月dd日 HH时mm分
19 | 分钟前
20 | 日前
21 |
22 |
--------------------------------------------------------------------------------
/GIF.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yilylong/DragableRecyclerView/c392b85c03a8eee24d6809c99e4c39c0dd95d911/GIF.gif
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # DragableRecyclerView [](https://jitpack.io/#yilylong/DragableRecyclerView)
2 | dragable and swipeable pullrefresh recyclerview--支持拖拽排序,侧滑删除,和下拉刷新上拉加载更多
3 |
4 |
5 |
6 | useage
7 | ---
8 |
9 | Step 1. Add the JitPack repository to your build file
10 | Add it in your root build.gradle at the end of repositories:
11 |
12 | allprojects {
13 | repositories {
14 | ...
15 | maven { url 'https://jitpack.io' }
16 | }
17 | }
18 |
19 | Step 2. Add the dependency
20 |
21 | dependencies {
22 | compile 'com.github.yilylong:DragableRecyclerView:v1.0.2'
23 | }
24 |
25 | in your xml:
26 | ---
27 |
32 |
33 | swipe menu
34 | ---
35 |
36 | // 是否开启侧滑
37 | mRecyclerView.setSwipeEnable(true);
38 | // 设置侧滑菜单
39 | mRecyclerView.setMenuCreator(new SwipeMenuCreator() {
40 | @Override
41 | public void create(SwipeMenu menu) {
42 | SwipeMenuItem deleteItem = new SwipeMenuItem(getApplicationContext());
43 | deleteItem.setBackground(R.color.colorAccent);
44 | deleteItem.setWidth(dp2px(MainActivity.this, 90));
45 | deleteItem.setTitle("删除");
46 | deleteItem.setIcon(R.mipmap.icon_delete);
47 | deleteItem.setTitleSize(18);
48 | deleteItem.setTitleColor(Color.WHITE);
49 | menu.addMenuItem(deleteItem);
50 |
51 | SwipeMenuItem collectionItem = new SwipeMenuItem(getApplicationContext());
52 | collectionItem.setBackground(R.color.green);
53 | collectionItem.setWidth(dp2px(MainActivity.this, 90));
54 | collectionItem.setTitle("收藏");
55 | collectionItem.setTitleSize(18);
56 | collectionItem.setTitleColor(Color.WHITE);
57 | collectionItem.setIcon(R.mipmap.icon_collection);
58 | menu.addMenuItem(collectionItem);
59 | }
60 | });
61 |
62 | // 设置侧滑菜单的监听
63 | mRecyclerView.setOnSwipedMenuItemClickListener(new DragableRecyclerView.OnSwipedMenuItemClickListener() {
64 |
65 | @Override
66 | public void onMenuItemClick(int position, RecyclerView.Adapter adapter, SwipeMenu menu, int index) {
67 | if(index==0){
68 | adapter.notifyItemRemoved(position);
69 | Toast.makeText(MainActivity.this,"删除第"+position+"项",Toast.LENGTH_SHORT).show();
70 | }else if(index==1){
71 | Toast.makeText(MainActivity.this,"收藏第"+position+"项",Toast.LENGTH_SHORT).show();
72 | }
73 | }
74 | });
75 |
76 | 长按拖拽排序
77 | ---
78 |
79 | // 是否可以长按拖拽
80 | mRecyclerView.setLongPressDragEnabled(true);
81 | // 设置长按拖拽的监听
82 | mRecyclerView.setOnItemDragListener(new DragableRecyclerView.OnItemDragListener() {
83 | @Override
84 | public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
85 | if(viewHolder!=null){
86 | viewHolder.itemView.setBackgroundResource(R.color.colorAccent);
87 | }
88 | }
89 | @Override
90 | public void onMoved(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, int fromPos, RecyclerView.ViewHolder target, int toPos, int x, int y) {
91 | String movedTX = Data.remove(fromPos);
92 | Data.add(toPos,movedTX);
93 | }
94 |
95 | @Override
96 | public boolean onDragScaleable() {
97 | return true;
98 | }
99 | @Override
100 | public void onDragCompleted(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
101 | viewHolder.itemView.setBackgroundResource(R.color.gray);
102 | }
103 | });
104 |
105 | 下拉刷新
106 | ---
107 |
108 | // 是否开启下拉刷新
109 | mRecyclerView.setPullRefreshEnable(true);
110 | // 是否开启上拉加载
111 | mRecyclerView.setPullLoadMoreEnable(true);
112 | // 设置下拉刷新的监听
113 | mRecyclerView.setPullRefreshListener(new DragableRecyclerView.OnPullRefreshListener() {
114 | @Override
115 | public void onRefresh() {
116 | mRecyclerView.postDelayed(new Runnable() {
117 | @Override
118 | public void run() {
119 | refresh();
120 | mRecyclerView.stopRefresh();
121 | }
122 | },3000);
123 | }
124 | @Override
125 | public void onLoadMore() {
126 |
127 | mRecyclerView.postDelayed(new Runnable() {
128 | @Override
129 | public void run() {
130 | loadMore();
131 | mRecyclerView.stopLoadMore();
132 | }
133 | },3000);
134 | }
135 | @Override
136 | public void onUpdateRefreshTime(long time) {
137 | mRecyclerView.setRefreshTime(time);
138 | }
139 | });
140 |
141 |
142 | 自定义刷新头
143 | ----
144 |
145 | 继承CBRefreshHeaderView,根据需要覆盖CBRefreshState中的各种状态方法,recyclerview会回调下拉刷新和上拉加载的各种方法。主要通过更改刷新头高度或者mragin来实现,参考CBRefreshHeader和CBRefreshFooter。
146 |
147 | // 设置自定义的下拉刷新和上拉加载刷新头
148 | mRecyclerView.setRefreshHeader(new CustomHeader(this));
149 | mRecyclerView.setLoadMoreFooter(new CustomFooter(this));
150 |
151 |
152 | 另外listview 版本的看这里:[CBPullRefreshListView](https://github.com/yilylong/CBPullRefreshListView)
153 | 感谢Xrecyclerview XlistView
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 25
5 | buildToolsVersion "25.0.3"
6 | defaultConfig {
7 | applicationId "com.zhl.dragablerecyclerview"
8 | minSdkVersion 14
9 | targetSdkVersion 25
10 | versionCode 1
11 | versionName "1.0"
12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | }
21 |
22 | dependencies {
23 | compile fileTree(dir: 'libs', include: ['*.jar'])
24 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
25 | exclude group: 'com.android.support', module: 'support-annotations'
26 | })
27 | compile 'com.android.support:appcompat-v7:25.3.1'
28 | compile 'com.android.support.constraint:constraint-layout:1.0.2'
29 | testCompile 'junit:junit:4.12'
30 | compile project(path: ':DragableRecyclerViewLib')
31 | }
32 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in D:\work\AndroidSDK/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
19 | # Uncomment this to preserve the line number information for
20 | # debugging stack traces.
21 | #-keepattributes SourceFile,LineNumberTable
22 |
23 | # If you keep the line number information, uncomment this to
24 | # hide the original source file name.
25 | #-renamesourcefileattribute SourceFile
26 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zhl/dragablerecyclerviewsample/CustomFooter.java:
--------------------------------------------------------------------------------
1 | package com.zhl.dragablerecyclerviewsample;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 | import android.view.Gravity;
6 | import android.view.LayoutInflater;
7 | import android.view.View;
8 | import android.view.ViewGroup;
9 | import android.widget.LinearLayout;
10 | import android.widget.RelativeLayout;
11 | import android.widget.TextView;
12 |
13 | import com.zhl.dragablerecyclerview.R;
14 | import com.zhl.dragablerecyclerview.view.CBRefreshHeaderView;
15 |
16 |
17 | public class CustomFooter extends CBRefreshHeaderView {
18 |
19 | private Context mContext;
20 | private LinearLayout footerViewContanier;
21 | private RelativeLayout mContentView;
22 | private View mProgressBar;
23 | private TextView mHintView;
24 | private int state;
25 |
26 | public CustomFooter(Context context) {
27 | super(context);
28 | initView(context);
29 | }
30 |
31 | public CustomFooter(Context context, AttributeSet attrs) {
32 | super(context, attrs);
33 | initView(context);
34 | }
35 |
36 | @Override
37 | public void setState(int state) {
38 | this.state = state;
39 | }
40 |
41 | @Override
42 | public int getState() {
43 | return state;
44 | }
45 |
46 | private void initView(Context context) {
47 | LayoutParams params =new LayoutParams(LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
48 | mContext = context;
49 | footerViewContanier = (LinearLayout) LayoutInflater.from(mContext).inflate(R.layout.cblistview_footer, null);
50 | mContentView = (RelativeLayout) footerViewContanier.findViewById(R.id.cbrefresh_footer_content);
51 | addView(footerViewContanier,params);
52 | setGravity(Gravity.TOP);
53 | mProgressBar = footerViewContanier.findViewById(R.id.cbrefresh_footer_progressbar);
54 | mHintView = (TextView) footerViewContanier.findViewById(R.id.cbrefresh_footer_hint_textview);
55 | }
56 |
57 | /**
58 | * set the footer bg
59 | *
60 | * @param resName
61 | */
62 | public void setFooterBg(int resName) {
63 | this.setBackgroundResource(resName);
64 | }
65 |
66 | @Override
67 | public void pullUpToLoadmore() {
68 | mProgressBar.setVisibility(View.GONE);
69 | mHintView.setVisibility(View.VISIBLE);
70 | mHintView.setText(getString(R.string.refresh_footer_tip_pullup_loadmore));
71 | }
72 |
73 | @Override
74 | public void releaseToLoadmore() {
75 | mProgressBar.setVisibility(View.GONE);
76 | mHintView.setVisibility(View.VISIBLE);
77 | mHintView.setText(getString(R.string.refresh_footer_tip_release_loadmore));
78 | }
79 |
80 | @Override
81 | public void onLoading() {
82 | mProgressBar.setVisibility(View.VISIBLE);
83 | mHintView.setVisibility(View.VISIBLE);
84 | mHintView.setText(getString(R.string.refresh_footer_tip_loading));
85 | }
86 |
87 | @Override
88 | public void onStyleChange(int state) {
89 | super.onStyleChange(state);
90 | }
91 |
92 | @Override
93 | public int getLoadMorePullUpDistance() {
94 | LayoutParams lp = (LayoutParams) mContentView.getLayoutParams();
95 | return lp.bottomMargin;
96 | }
97 |
98 | @Override
99 | public void setLoadMorePullUpDistance(int deltaY) {
100 | if (deltaY < 0)
101 | return;
102 | LayoutParams lp = (LayoutParams) mContentView.getLayoutParams();
103 | lp.bottomMargin = deltaY;
104 | mContentView.setLayoutParams(lp);
105 | }
106 |
107 | @Override
108 | public void footerViewShow() {
109 | LayoutParams lp = (LayoutParams) footerViewContanier.getLayoutParams();
110 | lp.height = LayoutParams.WRAP_CONTENT;
111 | footerViewContanier.setLayoutParams(lp);
112 | }
113 |
114 | @Override
115 | public void footerViewHide() {
116 | LayoutParams lp = (LayoutParams) footerViewContanier.getLayoutParams();
117 | lp.height = 0;
118 | footerViewContanier.setLayoutParams(lp);
119 | }
120 |
121 | @Override
122 | public int getRealHeaderContentHeight() {
123 | if (mContentView != null) {
124 | return mContentView.getHeight();
125 | }
126 | return 0;
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zhl/dragablerecyclerviewsample/CustomHeader.java:
--------------------------------------------------------------------------------
1 | package com.zhl.dragablerecyclerviewsample;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 | import android.view.Gravity;
6 | import android.view.LayoutInflater;
7 | import android.view.View;
8 | import android.view.animation.Animation;
9 | import android.view.animation.RotateAnimation;
10 | import android.widget.ImageView;
11 | import android.widget.LinearLayout;
12 | import android.widget.ProgressBar;
13 | import android.widget.RelativeLayout;
14 | import android.widget.TextView;
15 |
16 | import com.zhl.dragablerecyclerview.titanic.Titanic;
17 | import com.zhl.dragablerecyclerview.titanic.TitanicTextView;
18 | import com.zhl.dragablerecyclerview.view.CBRefreshHeaderView;
19 |
20 | /**
21 | * 描述:
22 | * Created by zhaohl on 2017-8-4.
23 | */
24 |
25 | public class CustomHeader extends CBRefreshHeaderView {
26 |
27 | private LinearLayout mContainer;
28 | private RelativeLayout mHeaderViewContent;
29 | private ImageView mArrowImageView;
30 | private ProgressBar mProgressBar;
31 | private TextView mHintTextView;
32 | private TextView mHeaderTimeView;
33 | // the curent state
34 | private int mState = STATE_PULL_TO_REFRESH;
35 | private Animation mRotateUpAnim;
36 | private Animation mRotateDownAnim;
37 | private final int ROTATE_ANIM_DURATION = 200;
38 | private TitanicTextView headrAnimView;
39 | private Titanic titanic;
40 |
41 | public CustomHeader(Context context) {
42 | this(context, null);
43 | }
44 |
45 | public CustomHeader(Context context, AttributeSet attrs) {
46 | this(context, attrs, -1);
47 | }
48 |
49 | public CustomHeader(Context context, AttributeSet attrs, int defStyleAttr) {
50 | super(context, attrs, defStyleAttr);
51 | initView(context);
52 | }
53 |
54 | private void initView(Context context) {
55 | // in the first set the Header height=0
56 | LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, 0);
57 | mContainer = (LinearLayout) LayoutInflater.from(context).inflate(R.layout.custom_header, null);
58 | mHeaderViewContent = (RelativeLayout) mContainer.findViewById(R.id.cbrefresh_header_content);
59 | mHeaderTimeView = (TextView) mContainer.findViewById(R.id.cbrefresh_header_time);
60 | addView(mContainer, lp);
61 | setGravity(Gravity.BOTTOM);
62 |
63 | mArrowImageView = (ImageView) findViewById(R.id.cbrefresh_header_arrow);
64 | mHintTextView = (TextView) findViewById(R.id.cbrefresh_header_hint_textview);
65 | mProgressBar = (ProgressBar) findViewById(R.id.cbrefresh_header_progressbar);
66 | headrAnimView = (TitanicTextView) findViewById(R.id.cbrefresh_header_anim);
67 | titanic = new Titanic();
68 | mRotateUpAnim = new RotateAnimation(0.0f, -180.0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
69 | mRotateUpAnim.setDuration(ROTATE_ANIM_DURATION);
70 | mRotateUpAnim.setFillAfter(true);
71 | mRotateDownAnim = new RotateAnimation(-180.0f, 0.0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
72 | mRotateDownAnim.setDuration(ROTATE_ANIM_DURATION);
73 | mRotateDownAnim.setFillAfter(true);
74 | }
75 |
76 | @Override
77 | public void setState(int state) {
78 | this.mState = state;
79 | }
80 |
81 | @Override
82 | public int getState() {
83 | return mState;
84 | }
85 |
86 | /**
87 | * @param resName
88 | */
89 | @Override
90 | public void setHeaderIcon(int resName) {
91 | mArrowImageView.setBackgroundResource(resName);
92 | }
93 |
94 | /**
95 | * set the footer bg
96 | *
97 | * @param resName
98 | */
99 | public void setHeaderBg(int resName) {
100 | this.setBackgroundResource(resName);
101 | }
102 |
103 | @Override
104 | public void pullToRefresh() {
105 | mHintTextView.setText(getString(R.string.refresh_header_tip_pull2refresh));
106 | mArrowImageView.setVisibility(View.VISIBLE);
107 | mProgressBar.setVisibility(View.INVISIBLE);
108 | if (mState == STATE_RELEASE_TO_REFRESH) {
109 | mArrowImageView.startAnimation(mRotateDownAnim);
110 | }
111 | if (mState == STATE_REFRESHING) {
112 | mArrowImageView.clearAnimation();
113 | }
114 | }
115 |
116 | @Override
117 | public void releaseToRefresh() {
118 | mHintTextView.setText(getString(R.string.refresh_header_tip_release2refresh));
119 | if (mState != STATE_RELEASE_TO_REFRESH) {
120 | mArrowImageView.clearAnimation();
121 | mArrowImageView.startAnimation(mRotateUpAnim);
122 | }
123 | }
124 |
125 | @Override
126 | public void onRefreshing() {
127 | mHintTextView.setText(getString(R.string.refresh_header_tip_refreshing));
128 | mArrowImageView.clearAnimation();
129 | mArrowImageView.setVisibility(View.INVISIBLE);
130 | mProgressBar.setVisibility(View.VISIBLE);
131 | }
132 |
133 | @Override
134 | public void onStyleChange(int state) {
135 | super.onStyleChange(state);
136 | }
137 |
138 | @Override
139 | public void setVisiableHeight(int height) {
140 | if (height < 0)
141 | height = 0;
142 | LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) mContainer.getLayoutParams();
143 | lp.height = height;
144 | mContainer.setLayoutParams(lp);
145 | }
146 |
147 | @Override
148 | public int getVisiableHeight() {
149 | return mContainer.getHeight();
150 | }
151 |
152 | @Override
153 | public int getRealHeaderContentHeight() {
154 | // beacuse container height =0 at the first ,so return mHeaderViewContent height
155 | if (mHeaderViewContent != null) {
156 | return mHeaderViewContent.getHeight();
157 | }
158 | return 0;
159 | }
160 |
161 | @Override
162 | public void setPullRefreshEnable(boolean enable) {
163 | if (!enable) { // disable, hide the content
164 | mHeaderViewContent.setVisibility(View.INVISIBLE);
165 | } else {
166 | mHeaderViewContent.setVisibility(View.VISIBLE);
167 | }
168 | }
169 |
170 | @Override
171 | public void setRefreshTime(String refreshTime) {
172 | mHeaderTimeView.setText(refreshTime);
173 | }
174 |
175 | @Override
176 | public void showHeaderAnim() {
177 | headrAnimView.setVisibility(VISIBLE);
178 | titanic.start(headrAnimView);
179 | }
180 |
181 | @Override
182 | public void stopHeaderAnim() {
183 | titanic.cancel();
184 | headrAnimView.setVisibility(GONE);
185 | }
186 |
187 | }
188 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zhl/dragablerecyclerviewsample/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.zhl.dragablerecyclerviewsample;
2 |
3 | import android.content.Context;
4 | import android.graphics.Color;
5 | import android.os.Bundle;
6 | import android.support.v7.app.AppCompatActivity;
7 | import android.support.v7.widget.LinearLayoutManager;
8 | import android.support.v7.widget.RecyclerView;
9 | import android.util.TypedValue;
10 | import android.view.LayoutInflater;
11 | import android.view.View;
12 | import android.view.ViewGroup;
13 | import android.widget.TextView;
14 | import android.widget.Toast;
15 |
16 | import com.zhl.dragablerecyclerview.swipemenu.SwipeMenu;
17 | import com.zhl.dragablerecyclerview.swipemenu.SwipeMenuCreator;
18 | import com.zhl.dragablerecyclerview.swipemenu.SwipeMenuItem;
19 | import com.zhl.dragablerecyclerview.view.DragableRecyclerView;
20 |
21 | import java.util.ArrayList;
22 |
23 | public class MainActivity extends AppCompatActivity {
24 | private DragableRecyclerView mRecyclerView;
25 | private ArrayList Data = new ArrayList();
26 | private MyAdapter adapter;
27 | @Override
28 | protected void onCreate(Bundle savedInstanceState) {
29 | super.onCreate(savedInstanceState);
30 | setContentView(R.layout.activity_main);
31 | initData();
32 | mRecyclerView = (DragableRecyclerView) findViewById(R.id.recyclerview);
33 | mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
34 | // 设置侧滑菜单
35 | mRecyclerView.setMenuCreator(new SwipeMenuCreator() {
36 | @Override
37 | public void create(SwipeMenu menu) {
38 | SwipeMenuItem deleteItem = new SwipeMenuItem(getApplicationContext());
39 | deleteItem.setBackground(R.color.colorAccent);
40 | deleteItem.setWidth(dp2px(MainActivity.this, 90));
41 | deleteItem.setTitle("删除");
42 | deleteItem.setIcon(R.mipmap.icon_delete);
43 | deleteItem.setTitleSize(18);
44 | deleteItem.setTitleColor(Color.WHITE);
45 | menu.addMenuItem(deleteItem);
46 |
47 | SwipeMenuItem collectionItem = new SwipeMenuItem(getApplicationContext());
48 | collectionItem.setBackground(R.color.green);
49 | collectionItem.setWidth(dp2px(MainActivity.this, 90));
50 | collectionItem.setTitle("收藏");
51 | collectionItem.setTitleSize(18);
52 | collectionItem.setTitleColor(Color.WHITE);
53 | collectionItem.setIcon(R.mipmap.icon_collection);
54 | menu.addMenuItem(collectionItem);
55 | }
56 | });
57 | // 开启刷新头动画
58 | mRecyclerView.showHeaderAnim();
59 | // 是否开启侧滑
60 | mRecyclerView.setSwipeEnable(true);
61 | // 是否可以长按拖拽
62 | mRecyclerView.setLongPressDragEnabled(true);
63 | // 设置自定义的下拉刷新和上拉加载刷新头
64 | // mRecyclerView.setRefreshHeader(new CustomHeader(this));
65 | // mRecyclerView.setLoadMoreFooter(new CustomFooter(this));
66 | mRecyclerView.setAdapter(adapter = new MyAdapter());
67 | // 是否开启下拉刷新
68 | mRecyclerView.setPullRefreshEnable(true);
69 | // 是否开启上拉加载
70 | mRecyclerView.setPullLoadMoreEnable(true);
71 | // 设置长按拖拽的监听
72 | mRecyclerView.setOnItemDragListener(new DragableRecyclerView.OnItemDragListener() {
73 | @Override
74 | public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
75 | if(viewHolder!=null){
76 | viewHolder.itemView.setBackgroundResource(R.color.colorAccent);
77 | }
78 | }
79 | @Override
80 | public void onMoved(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, int fromPos, RecyclerView.ViewHolder target, int toPos, int x, int y) {
81 | String movedTX = Data.remove(fromPos);
82 | Data.add(toPos,movedTX);
83 | }
84 |
85 | @Override
86 | public boolean onDragScaleable() {
87 | return true;
88 | }
89 | @Override
90 | public void onDragCompleted(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
91 | viewHolder.itemView.setBackgroundResource(R.color.gray);
92 | }
93 | });
94 | // 设置侧滑菜单的监听
95 | mRecyclerView.setOnSwipedMenuItemClickListener(new DragableRecyclerView.OnSwipedMenuItemClickListener() {
96 |
97 | @Override
98 | public void onMenuItemClick(int position, RecyclerView.Adapter adapter, SwipeMenu menu, int index) {
99 | if(index==0){
100 | adapter.notifyItemRemoved(position);
101 | Toast.makeText(MainActivity.this,"删除第"+position+"项",Toast.LENGTH_SHORT).show();
102 | }else if(index==1){
103 | Toast.makeText(MainActivity.this,"收藏第"+position+"项",Toast.LENGTH_SHORT).show();
104 | }
105 | }
106 | });
107 | // 设置recyclerview的item点击监听
108 | mRecyclerView.setOnItemClickListener(new DragableRecyclerView.OnItemClickListener() {
109 | @Override
110 | public void onItemClick(int position, RecyclerView.Adapter adapter, View ConvertView) {
111 | Toast.makeText(MainActivity.this,"点击第"+position+"项",Toast.LENGTH_SHORT).show();
112 | }
113 | });
114 | // 设置下拉刷新的监听
115 | mRecyclerView.setPullRefreshListener(new DragableRecyclerView.OnPullRefreshListener() {
116 | @Override
117 | public void onRefresh() {
118 | mRecyclerView.postDelayed(new Runnable() {
119 | @Override
120 | public void run() {
121 | refresh();
122 | mRecyclerView.stopRefresh();
123 | }
124 | },3000);
125 | }
126 | @Override
127 | public void onLoadMore() {
128 |
129 | mRecyclerView.postDelayed(new Runnable() {
130 | @Override
131 | public void run() {
132 | loadMore();
133 | mRecyclerView.stopLoadMore();
134 | }
135 | },3000);
136 | }
137 | @Override
138 | public void onUpdateRefreshTime(long time) {
139 | mRecyclerView.setRefreshTime(time);
140 | }
141 | });
142 | }
143 |
144 | private void refresh() {
145 | Data.clear();
146 | initData();
147 | adapter.notifyDataSetChanged();
148 | }
149 |
150 | private void loadMore() {
151 | for(int i=0;i<10;i++){
152 | Data.add("load more "+i);
153 | }
154 | adapter.notifyItemRangeInserted(mRecyclerView.getAdapter().getItemCount(),10);
155 | }
156 |
157 | private void initData() {
158 | for(int i=0;i<50;i++){
159 | Data.add("MaterialDesign_"+i);
160 | }
161 | }
162 |
163 | private class MyAdapter extends RecyclerView.Adapter{
164 | @Override
165 | public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
166 | View view = LayoutInflater.from(MainActivity.this).inflate(R.layout.item_recycler,parent,false);
167 | return new MyViewHolder(view);
168 | }
169 |
170 | @Override
171 | public void onBindViewHolder(MyViewHolder holder, int position) {
172 | holder.itemText.setText(Data.get(position));
173 | }
174 |
175 | @Override
176 | public int getItemCount() {
177 | return Data.size();
178 | }
179 | }
180 |
181 | private class MyViewHolder extends RecyclerView.ViewHolder{
182 | private TextView itemText;
183 | public MyViewHolder(View itemView) {
184 | super(itemView);
185 | itemText = (TextView) itemView.findViewById(R.id.item_tx);
186 | }
187 | }
188 |
189 | public int dp2px(Context context, int dp) {
190 | return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, context.getResources().getDisplayMetrics());
191 | }
192 | }
193 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/custom_footer.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
14 |
23 |
24 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/custom_header.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
11 |
12 |
26 |
27 |
35 |
36 |
44 |
45 |
49 |
50 |
57 |
58 |
64 |
65 |
66 |
67 |
75 |
76 |
85 |
86 |
87 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_recycler.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yilylong/DragableRecyclerView/c392b85c03a8eee24d6809c99e4c39c0dd95d911/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yilylong/DragableRecyclerView/c392b85c03a8eee24d6809c99e4c39c0dd95d911/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yilylong/DragableRecyclerView/c392b85c03a8eee24d6809c99e4c39c0dd95d911/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yilylong/DragableRecyclerView/c392b85c03a8eee24d6809c99e4c39c0dd95d911/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yilylong/DragableRecyclerView/c392b85c03a8eee24d6809c99e4c39c0dd95d911/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yilylong/DragableRecyclerView/c392b85c03a8eee24d6809c99e4c39c0dd95d911/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yilylong/DragableRecyclerView/c392b85c03a8eee24d6809c99e4c39c0dd95d911/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yilylong/DragableRecyclerView/c392b85c03a8eee24d6809c99e4c39c0dd95d911/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/icon_collection.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yilylong/DragableRecyclerView/c392b85c03a8eee24d6809c99e4c39c0dd95d911/app/src/main/res/mipmap-xxhdpi/icon_collection.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/icon_delete.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yilylong/DragableRecyclerView/c392b85c03a8eee24d6809c99e4c39c0dd95d911/app/src/main/res/mipmap-xxhdpi/icon_delete.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yilylong/DragableRecyclerView/c392b85c03a8eee24d6809c99e4c39c0dd95d911/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yilylong/DragableRecyclerView/c392b85c03a8eee24d6809c99e4c39c0dd95d911/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 | #3fbecc
7 | #efefef
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | DragableRecyclerView
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:2.3.3'
9 |
10 | // NOTE: Do not place your application dependencies here; they belong
11 | // in the individual module build.gradle files
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | jcenter()
18 | }
19 | }
20 |
21 | task clean(type: Delete) {
22 | delete rootProject.buildDir
23 | }
24 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | org.gradle.jvmargs=-Xmx1536m
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | # org.gradle.parallel=true
18 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yilylong/DragableRecyclerView/c392b85c03a8eee24d6809c99e4c39c0dd95d911/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Tue Aug 01 15:32:10 CST 2017
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':DragableRecyclerViewLib'
2 |
--------------------------------------------------------------------------------