├── .gitignore
├── LICENSE
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ ├── com
│ │ └── lorentzos
│ │ │ └── flingswipe
│ │ │ ├── BaseFlingAdapterView.java
│ │ │ ├── FlingCardListener.java
│ │ │ ├── LinearRegression.java
│ │ │ └── SwipeFlingAdapterView.java
│ └── me
│ │ └── payge
│ │ └── swipecardview
│ │ └── MainActivity.java
│ └── res
│ ├── drawable-xxhdpi
│ ├── default_card.png
│ ├── home01_bg_card.9.png
│ ├── home01_btn_collect.png
│ ├── home01_icon_edu.png
│ ├── home01_icon_location.png
│ ├── home01_icon_work_year.png
│ ├── i1.jpg
│ ├── i2.jpg
│ ├── i3.jpg
│ ├── i4.jpg
│ ├── i5.jpg
│ └── i6.jpg
│ ├── drawable
│ └── bg_button.xml
│ ├── layout
│ ├── activity_main.xml
│ └── card_new_item.xml
│ ├── mipmap-hdpi
│ └── ic_launcher.png
│ ├── mipmap-mdpi
│ └── ic_launcher.png
│ ├── mipmap-xhdpi
│ └── ic_launcher.png
│ ├── mipmap-xxhdpi
│ └── ic_launcher.png
│ ├── mipmap-xxxhdpi
│ └── ic_launcher.png
│ ├── values-w820dp
│ └── dimens.xml
│ └── values
│ ├── colors.xml
│ ├── dimens.xml
│ ├── strings.xml
│ ├── styles.xml
│ └── swipe_fling_view.xml
├── build.gradle
├── ezgif.com.gif
├── 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 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # SwipeCardView
2 | SwipeCardView是基于Diolor的[Swipecards](https://github.com/Diolor/Swipecards)控件改进实现,SwipeCardView是一个优雅的刷脸控件,滑动刷脸伴随渐变层叠动画,带来前所未有的滑动刷脸体验。
3 |
4 | thanks Diolor [Swipecards](https://github.com/Diolor/Swipecards)
5 |
6 | ## Screenshot
7 | 
8 |
9 | ## Relative Project
10 | [SwipeAdapterView](https://github.com/xiepeijie/SwipeAdapterView)
11 |
12 | ## Usage
13 | ### XML:
14 | ```
15 |
22 | ```
23 | ### Java Code:
24 | ```
25 | swipeView = (SwipeFlingAdapterView) findViewById(R.id.swipe_view);
26 | swipeView.setIsNeedSwipe(true);// 是否开启swipe滑动效果,当不调用此方法设置时,默认开启。
27 | swipeView.setFlingListener(this);
28 | swipeView.setOnItemClickListener(this);
29 | ```
30 | **onFlingListener**
31 | ```
32 | @Override
33 | public void removeFirstObjectInAdapter() {
34 | adapter.remove(0);
35 | }
36 |
37 | @Override
38 | public void onLeftCardExit(Object dataObject) {
39 | // to do something
40 | }
41 |
42 | @Override
43 | public void onRightCardExit(Object dataObject) {
44 | // to do something
45 | }
46 |
47 | @Override
48 | public void onAdapterAboutToEmpty(int itemsInAdapter) {
49 | if (itemsInAdapter == 3) {
50 | loadData();
51 | }
52 | }
53 | ```
54 | **Click to swipe**
55 |
56 | ```
57 | @Override
58 | public void onClick(View v) {
59 | // swipe left
60 | swipeView.swipeLeft();
61 | // swipe right
62 | //swipeView.swipeRight();
63 | }
64 | ```
65 |
66 | # About me
67 | 微博:[@萧雾宇](http://weibo.com/payge)
68 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 23
5 | buildToolsVersion "25.0.0"
6 |
7 | defaultConfig {
8 | applicationId "me.payge.swipecardview"
9 | minSdkVersion 14
10 | targetSdkVersion 23
11 | versionCode 1
12 | versionName "1.0"
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(include: ['*.jar'], dir: 'libs')
24 | testCompile 'junit:junit:4.12'
25 | compile 'com.android.support:appcompat-v7:23.4.0'
26 | }
27 |
--------------------------------------------------------------------------------
/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 E:\IDE\Android\sdk/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 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/app/src/main/java/com/lorentzos/flingswipe/BaseFlingAdapterView.java:
--------------------------------------------------------------------------------
1 | package com.lorentzos.flingswipe;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 | import android.widget.AdapterView;
6 |
7 | /**
8 | * Created by dionysis_lorentzos on 6/8/14
9 | * for package com.lorentzos.swipecards
10 | * and project Swipe cards.
11 | * Use with caution dinausaurs might appear!
12 | */
13 | abstract class BaseFlingAdapterView extends AdapterView {
14 |
15 | private int heightMeasureSpec;
16 | private int widthMeasureSpec;
17 |
18 |
19 |
20 | public BaseFlingAdapterView(Context context) {
21 | super(context);
22 | }
23 |
24 | public BaseFlingAdapterView(Context context, AttributeSet attrs) {
25 | super(context, attrs);
26 | }
27 |
28 | public BaseFlingAdapterView(Context context, AttributeSet attrs, int defStyle) {
29 | super(context, attrs, defStyle);
30 | }
31 |
32 | @Override
33 | public void setSelection(int i) {
34 | throw new UnsupportedOperationException("Not supported");
35 | }
36 |
37 | @Override
38 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
39 | super.onMeasure(widthMeasureSpec, heightMeasureSpec);
40 | this.widthMeasureSpec = widthMeasureSpec;
41 | this.heightMeasureSpec = heightMeasureSpec;
42 | }
43 |
44 |
45 | public int getWidthMeasureSpec() {
46 | return widthMeasureSpec;
47 | }
48 |
49 | public int getHeightMeasureSpec() {
50 | return heightMeasureSpec;
51 | }
52 |
53 |
54 |
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/app/src/main/java/com/lorentzos/flingswipe/FlingCardListener.java:
--------------------------------------------------------------------------------
1 | package com.lorentzos.flingswipe;
2 |
3 | import android.animation.Animator;
4 | import android.animation.AnimatorListenerAdapter;
5 | import android.view.MotionEvent;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 | import android.view.animation.LinearInterpolator;
9 | import android.view.animation.OvershootInterpolator;
10 |
11 | /**
12 | * Created by dionysis_lorentzos on 5/8/14
13 | * for package com.lorentzos.swipecards
14 | * and project Swipe cards.
15 | * Use with caution dinausaurs might appear!
16 | */
17 | public class FlingCardListener implements View.OnTouchListener {
18 |
19 | private final float objectX;
20 | private final float objectY;
21 | private final int objectH;
22 | private final int objectW;
23 | private final int parentWidth;
24 | private final FlingListener mFlingListener;
25 | private final Object dataObject;
26 | private final float halfWidth;
27 | private float BASE_ROTATION_DEGREES;
28 |
29 | private float aPosX;
30 | private float aPosY;
31 | private float aDownTouchX;
32 | private float aDownTouchY;
33 | private static final int INVALID_POINTER_ID = -1;
34 |
35 | // The active pointer is the one currently moving our object.
36 | private int mActivePointerId = INVALID_POINTER_ID;
37 | private View frame = null;
38 |
39 | private final int TOUCH_ABOVE = 0;
40 | private final int TOUCH_BELOW = 1;
41 | private int touchPosition;
42 | // private final Object obj = new Object();
43 | private boolean isAnimationRunning = false;
44 | private float MAX_COS = (float) Math.cos(Math.toRadians(45));
45 | // 支持左右滑
46 | private boolean isNeedSwipe = true;
47 |
48 | private float aTouchUpX;
49 |
50 | private int animDuration = 300;
51 | private float scale;
52 |
53 | /**
54 | * every time we touch down,we should stop the {@link #animRun}
55 | */
56 | private boolean resetAnimCanceled = false;
57 |
58 | public FlingCardListener(View frame, Object itemAtPosition, float rotation_degrees, FlingListener flingListener) {
59 | super();
60 | this.frame = frame;
61 | this.objectX = frame.getX();
62 | this.objectY = frame.getY();
63 | this.objectW = frame.getWidth();
64 | this.objectH = frame.getHeight();
65 | this.halfWidth = objectW/2f;
66 | this.dataObject = itemAtPosition;
67 | this.parentWidth = ((ViewGroup) frame.getParent()).getWidth();
68 | this.BASE_ROTATION_DEGREES = rotation_degrees;
69 | this.mFlingListener = flingListener;
70 | }
71 |
72 | public void setIsNeedSwipe(boolean isNeedSwipe) {
73 | this.isNeedSwipe = isNeedSwipe;
74 | }
75 |
76 | @Override
77 | public boolean onTouch(View view, MotionEvent event) {
78 |
79 | try {
80 | switch (event.getAction() & MotionEvent.ACTION_MASK) {
81 | case MotionEvent.ACTION_DOWN:
82 |
83 | // remove the listener because 'onAnimationEnd' will still be called if we cancel the animation.
84 | this.frame.animate().setListener(null);
85 | this.frame.animate().cancel();
86 |
87 | resetAnimCanceled = true;
88 |
89 | // Save the ID of this pointer
90 | mActivePointerId = event.getPointerId(0);
91 | final float x = event.getX(mActivePointerId);
92 | final float y = event.getY(mActivePointerId);
93 |
94 | // Remember where we started
95 | aDownTouchX = x;
96 | aDownTouchY = y;
97 | // to prevent an initial jump of the magnifier, aposX and aPosY must
98 | // have the values from the magnifier frame
99 | aPosX = frame.getX();
100 | aPosY = frame.getY();
101 |
102 | if (y < objectH/2) {
103 | touchPosition = TOUCH_ABOVE;
104 | } else {
105 | touchPosition = TOUCH_BELOW;
106 | }
107 | break;
108 |
109 | case MotionEvent.ACTION_POINTER_DOWN:
110 | break;
111 |
112 | case MotionEvent.ACTION_POINTER_UP:
113 | // Extract the index of the pointer that left the touch sensor
114 | final int pointerIndex = (event.getAction() &
115 | MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
116 | final int pointerId = event.getPointerId(pointerIndex);
117 | if (pointerId == mActivePointerId) {
118 | // This was our active pointer going up. Choose a new
119 | // active pointer and adjust accordingly.
120 | final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
121 | mActivePointerId = event.getPointerId(newPointerIndex);
122 | }
123 | break;
124 | case MotionEvent.ACTION_MOVE:
125 |
126 | // Find the index of the active pointer and fetch its position
127 | final int pointerIndexMove = event.findPointerIndex(mActivePointerId);
128 | final float xMove = event.getX(pointerIndexMove);
129 | final float yMove = event.getY(pointerIndexMove);
130 |
131 | // from http://android-developers.blogspot.com/2010/06/making-sense-of-multitouch.html
132 | // Calculate the distance moved
133 | final float dx = xMove - aDownTouchX;
134 | final float dy = yMove - aDownTouchY;
135 |
136 | // Move the frame
137 | aPosX += dx;
138 | aPosY += dy;
139 |
140 | // calculate the rotation degrees
141 | float distObjectX = aPosX - objectX;
142 | float rotation = BASE_ROTATION_DEGREES * 2f * distObjectX / parentWidth;
143 | if (touchPosition == TOUCH_BELOW) {
144 | rotation = -rotation;
145 | }
146 |
147 | // in this area would be code for doing something with the view as the frame moves.
148 | if (isNeedSwipe) {
149 | frame.setX(aPosX);
150 | frame.setY(aPosY);
151 | frame.setRotation(rotation);
152 | mFlingListener.onScroll(getScrollProgress(), getScrollXProgressPercent());
153 | }
154 | break;
155 |
156 | case MotionEvent.ACTION_UP:
157 | case MotionEvent.ACTION_CANCEL:
158 | //mActivePointerId = INVALID_POINTER_ID;
159 | int pointerCount = event.getPointerCount();
160 | int activePointerId = Math.min(mActivePointerId, pointerCount - 1);
161 | aTouchUpX = event.getX(activePointerId);
162 | mActivePointerId = INVALID_POINTER_ID;
163 | resetCardViewOnStack(event);
164 | break;
165 |
166 | }
167 | } catch (Exception e) {
168 | e.printStackTrace();
169 | }
170 |
171 | return true;
172 | }
173 |
174 |
175 | private float getScrollProgress() {
176 | float dx = aPosX - objectX;
177 | float dy = aPosY - objectY;
178 | float dis = Math.abs(dx) + Math.abs(dy);
179 | return Math.min(dis, 400f) / 400f;
180 | }
181 |
182 | private float getScrollXProgressPercent() {
183 | if (movedBeyondLeftBorder()) {
184 | return -1f;
185 | } else if (movedBeyondRightBorder()) {
186 | return 1f;
187 | } else {
188 | float zeroToOneValue = (aPosX + halfWidth - leftBorder()) / (rightBorder() - leftBorder());
189 | return zeroToOneValue * 2f - 1f;
190 | }
191 | }
192 |
193 | private boolean resetCardViewOnStack(MotionEvent event) {
194 | if (isNeedSwipe) {
195 | final int duration = 200;
196 | if(movedBeyondLeftBorder()){
197 | // Left Swipe
198 | onSelected(true, getExitPoint(-objectW), duration);
199 | mFlingListener.onScroll(1f, -1.0f);
200 | }else if(movedBeyondRightBorder()) {
201 | // Right Swipe
202 | onSelected(false, getExitPoint(parentWidth), duration);
203 | mFlingListener.onScroll(1f, 1.0f);
204 | }else{
205 | float absMoveXDistance = Math.abs(aPosX-objectX);
206 | float absMoveYDistance = Math.abs(aPosY-objectY);
207 | if(absMoveXDistance < 4 && absMoveYDistance < 4){
208 | mFlingListener.onClick(event, frame, dataObject);
209 | }else{
210 | frame.animate()
211 | .setDuration(animDuration)
212 | .setInterpolator(new OvershootInterpolator(1.5f))
213 | .x(objectX)
214 | .y(objectY)
215 | .rotation(0)
216 | .start();
217 | scale = getScrollProgress();
218 | this.frame.postDelayed(animRun, 0);
219 | resetAnimCanceled = false;
220 | }
221 | aPosX = 0;
222 | aPosY = 0;
223 | aDownTouchX = 0;
224 | aDownTouchY = 0;
225 | }
226 | } else {
227 | float distanceX = Math.abs(aTouchUpX - aDownTouchX);
228 | if(distanceX < 4)
229 | mFlingListener.onClick(event, frame, dataObject);
230 | }
231 | return false;
232 | }
233 |
234 | private Runnable animRun = new Runnable() {
235 | @Override
236 | public void run() {
237 | mFlingListener.onScroll(scale, 0);
238 | if (scale > 0 && !resetAnimCanceled) {
239 | scale = scale - 0.1f;
240 | if (scale < 0)
241 | scale = 0;
242 | frame.postDelayed(this, animDuration / 20);
243 | }
244 | }
245 | };
246 |
247 | private boolean movedBeyondLeftBorder() {
248 | return aPosX+halfWidth < leftBorder();
249 | }
250 |
251 | private boolean movedBeyondRightBorder() {
252 | return aPosX+halfWidth > rightBorder();
253 | }
254 |
255 |
256 | public float leftBorder(){
257 | return parentWidth/4f;
258 | }
259 |
260 | public float rightBorder(){
261 | return 3*parentWidth/4f;
262 | }
263 |
264 |
265 | public void onSelected(final boolean isLeft, float exitY, long duration){
266 | isAnimationRunning = true;
267 | float exitX;
268 | if(isLeft) {
269 | exitX = -objectW-getRotationWidthOffset();
270 | }else {
271 | exitX = parentWidth+getRotationWidthOffset();
272 | }
273 |
274 | this.frame.animate()
275 | .setDuration(duration)
276 | .setInterpolator(new LinearInterpolator())
277 | .translationX(exitX)
278 | .translationY(exitY)
279 | //.rotation(isLeft ? -BASE_ROTATION_DEGREES:BASE_ROTATION_DEGREES)
280 | .setListener(new AnimatorListenerAdapter() {
281 | @Override
282 | public void onAnimationEnd(Animator animation) {
283 | if (isLeft) {
284 | mFlingListener.onCardExited();
285 | mFlingListener.leftExit(dataObject);
286 | } else {
287 | mFlingListener.onCardExited();
288 | mFlingListener.rightExit(dataObject);
289 | }
290 | isAnimationRunning = false;
291 | }
292 | }).start();
293 | }
294 |
295 | /**
296 | * Starts a default left exit animation.
297 | */
298 | public void selectLeft(){
299 | if(!isAnimationRunning)
300 | selectLeft(animDuration);
301 | }
302 | /**
303 | * Starts a default left exit animation.
304 | */
305 | public void selectLeft(long duration){
306 | if(!isAnimationRunning)
307 | onSelected(true, objectY, duration);
308 | }
309 |
310 | /**
311 | * Starts a default right exit animation.
312 | */
313 | public void selectRight(){
314 | if(!isAnimationRunning)
315 | selectRight(animDuration);
316 | }
317 | /**
318 | * Starts a default right exit animation.
319 | */
320 | public void selectRight(long duration){
321 | if(!isAnimationRunning)
322 | onSelected(false, objectY, duration);
323 | }
324 |
325 | private float getExitPoint(int exitXPoint) {
326 | float[] x = new float[2];
327 | x[0] = objectX;
328 | x[1] = aPosX;
329 |
330 | float[] y = new float[2];
331 | y[0] = objectY;
332 | y[1] = aPosY;
333 |
334 | LinearRegression regression = new LinearRegression(x,y);
335 |
336 | //Your typical y = ax+b linear regression
337 | return (float) regression.slope() * exitXPoint + (float) regression.intercept();
338 | }
339 |
340 | private float getExitRotation(boolean isLeft){
341 | float rotation = BASE_ROTATION_DEGREES * 2f * (parentWidth - objectX)/parentWidth;
342 | if (touchPosition == TOUCH_BELOW) {
343 | rotation = -rotation;
344 | }
345 | if(isLeft){
346 | rotation = -rotation;
347 | }
348 | return rotation;
349 | }
350 |
351 | /**
352 | * When the object rotates it's width becomes bigger.
353 | * The maximum width is at 45 degrees.
354 | *
355 | * The below method calculates the width offset of the rotation.
356 | *
357 | */
358 | private float getRotationWidthOffset() {
359 | return objectW/MAX_COS - objectW;
360 | }
361 |
362 |
363 | public void setRotationDegrees(float degrees) {
364 | this.BASE_ROTATION_DEGREES = degrees;
365 | }
366 |
367 |
368 | protected interface FlingListener {
369 | void onCardExited();
370 | void leftExit(Object dataObject);
371 | void rightExit(Object dataObject);
372 | void onClick(MotionEvent event, View v, Object dataObject);
373 | void onScroll(float progress, float scrollXProgress);
374 | }
375 |
376 |
377 | }
378 |
379 |
--------------------------------------------------------------------------------
/app/src/main/java/com/lorentzos/flingswipe/LinearRegression.java:
--------------------------------------------------------------------------------
1 | package com.lorentzos.flingswipe;
2 |
3 |
4 | /*************************************************************************
5 | * Compilation: javac LinearRegression.java
6 | * Execution: java LinearRegression
7 | *
8 | * Compute least squares solution to y = beta * x + alpha.
9 | * Simple linear regression.
10 | *
11 | *************************************************************************/
12 |
13 |
14 | /**
15 | * The LinearRegression class performs a simple linear regression
16 | * on an set of N data points (yi, xi).
17 | * That is, it fits a straight line y = α + β x,
18 | * (where y is the response variable, x is the predictor variable,
19 | * α is the y-intercept, and β is the slope)
20 | * that minimizes the sum of squared residuals of the linear regression model.
21 | * It also computes associated statistics, including the coefficient of
22 | * determination R2 and the standard deviation of the
23 | * estimates for the slope and y-intercept.
24 | *
25 | * @author Robert Sedgewick
26 | * @author Kevin Wayne
27 | */
28 | public class LinearRegression {
29 | private final int N;
30 | private final double alpha, beta;
31 | private final double R2;
32 | private final double svar, svar0, svar1;
33 |
34 | /**
35 | * Performs a linear regression on the data points (y[i], x[i]).
36 | * @param x the values of the predictor variable
37 | * @param y the corresponding values of the response variable
38 | * @throws IllegalArgumentException if the lengths of the two arrays are not equal
39 | */
40 | public LinearRegression(float[] x, float[] y) {
41 | if (x.length != y.length) {
42 | throw new IllegalArgumentException("array lengths are not equal");
43 | }
44 | N = x.length;
45 |
46 | // first pass
47 | double sumx = 0.0, sumy = 0.0, sumx2 = 0.0;
48 | for (int i = 0; i < N; i++) sumx += x[i];
49 | for (int i = 0; i < N; i++) sumx2 += x[i]*x[i];
50 | for (int i = 0; i < N; i++) sumy += y[i];
51 | double xbar = sumx / N;
52 | double ybar = sumy / N;
53 |
54 | // second pass: compute summary statistics
55 | double xxbar = 0.0, yybar = 0.0, xybar = 0.0;
56 | for (int i = 0; i < N; i++) {
57 | xxbar += (x[i] - xbar) * (x[i] - xbar);
58 | yybar += (y[i] - ybar) * (y[i] - ybar);
59 | xybar += (x[i] - xbar) * (y[i] - ybar);
60 | }
61 | beta = xybar / xxbar;
62 | alpha = ybar - beta * xbar;
63 |
64 | // more statistical analysis
65 | double rss = 0.0; // residual sum of squares
66 | double ssr = 0.0; // regression sum of squares
67 | for (int i = 0; i < N; i++) {
68 | double fit = beta*x[i] + alpha;
69 | rss += (fit - y[i]) * (fit - y[i]);
70 | ssr += (fit - ybar) * (fit - ybar);
71 | }
72 |
73 | int degreesOfFreedom = N-2;
74 | R2 = ssr / yybar;
75 | svar = rss / degreesOfFreedom;
76 | svar1 = svar / xxbar;
77 | svar0 = svar/N + xbar*xbar*svar1;
78 | }
79 |
80 | /**
81 | * Returns the y-intercept α of the best of the best-fit line y = α + β x.
82 | * @return the y-intercept α of the best-fit line y = α + β x
83 | */
84 | public double intercept() {
85 | return alpha;
86 | }
87 |
88 | /**
89 | * Returns the slope β of the best of the best-fit line y = α + β x.
90 | * @return the slope β of the best-fit line y = α + β x
91 | */
92 | public double slope() {
93 | return beta;
94 | }
95 |
96 | /**
97 | * Returns the coefficient of determination R2.
98 | * @return the coefficient of determination R2, which is a real number between 0 and 1
99 | */
100 | public double R2() {
101 | return R2;
102 | }
103 |
104 | /**
105 | * Returns the standard error of the estimate for the intercept.
106 | * @return the standard error of the estimate for the intercept
107 | */
108 | public double interceptStdErr() {
109 | return Math.sqrt(svar0);
110 | }
111 |
112 | /**
113 | * Returns the standard error of the estimate for the slope.
114 | * @return the standard error of the estimate for the slope
115 | */
116 | public double slopeStdErr() {
117 | return Math.sqrt(svar1);
118 | }
119 |
120 | /**
121 | * Returns the expected response y given the value of the predictor
122 | * variable x.
123 | * @param x the value of the predictor variable
124 | * @return the expected response y given the value of the predictor
125 | * variable x
126 | */
127 | public double predict(double x) {
128 | return beta*x + alpha;
129 | }
130 |
131 | /**
132 | * Returns a string representation of the simple linear regression model.
133 | * @return a string representation of the simple linear regression model,
134 | * including the best-fit line and the coefficient of determination R2
135 | */
136 | public String toString() {
137 | String s = "";
138 | s += String.format("%.2f N + %.2f", slope(), intercept());
139 | return s + " (R^2 = " + String.format("%.3f", R2()) + ")";
140 | }
141 |
142 |
143 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/lorentzos/flingswipe/SwipeFlingAdapterView.java:
--------------------------------------------------------------------------------
1 | package com.lorentzos.flingswipe;
2 |
3 | import android.annotation.TargetApi;
4 | import android.content.Context;
5 | import android.content.res.TypedArray;
6 | import android.database.DataSetObserver;
7 | import android.os.Build;
8 | import android.util.AttributeSet;
9 | import android.util.Log;
10 | import android.view.Gravity;
11 | import android.view.MotionEvent;
12 | import android.view.View;
13 | import android.widget.Adapter;
14 | import android.widget.FrameLayout;
15 |
16 | import java.util.ArrayList;
17 |
18 | import me.payge.swipecardview.R;
19 |
20 |
21 | /**
22 | * Created by dionysis_lorentzos on 5/8/14
23 | * for package com.lorentzos.swipecards
24 | * and project Swipe cards.
25 | * Use with caution dinosaurs might appear!
26 | */
27 |
28 | public class SwipeFlingAdapterView extends BaseFlingAdapterView {
29 |
30 | private ArrayList cacheItems = new ArrayList<>();
31 |
32 | //缩放层叠效果
33 | private int yOffsetStep; // view叠加垂直偏移量的步长
34 | private static final float SCALE_STEP = 0.08f; // view叠加缩放的步长
35 | //缩放层叠效果
36 |
37 | private int MAX_VISIBLE = 4; // 值建议最小为4
38 | private int MIN_ADAPTER_STACK = 6;
39 | private float ROTATION_DEGREES = 2f;
40 | private int LAST_OBJECT_IN_STACK = 0;
41 |
42 | private Adapter mAdapter;
43 | private onFlingListener mFlingListener;
44 | private AdapterDataSetObserver mDataSetObserver;
45 | private boolean mInLayout = false;
46 | private View mActiveCard = null;
47 | private OnItemClickListener mOnItemClickListener;
48 | private FlingCardListener flingCardListener;
49 |
50 | // 支持左右滑
51 | public boolean isNeedSwipe = true;
52 |
53 | private int initTop;
54 | private int initLeft;
55 |
56 | public SwipeFlingAdapterView(Context context) {
57 | this(context, null);
58 | }
59 |
60 | public SwipeFlingAdapterView(Context context, AttributeSet attrs) {
61 | this(context, attrs, 0);
62 | }
63 |
64 | public SwipeFlingAdapterView(Context context, AttributeSet attrs, int defStyle) {
65 | super(context, attrs, defStyle);
66 |
67 | TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SwipeFlingAdapterView, defStyle, 0);
68 | MAX_VISIBLE = a.getInt(R.styleable.SwipeFlingAdapterView_max_visible, MAX_VISIBLE);
69 | MIN_ADAPTER_STACK = a.getInt(R.styleable.SwipeFlingAdapterView_min_adapter_stack, MIN_ADAPTER_STACK);
70 | ROTATION_DEGREES = a.getFloat(R.styleable.SwipeFlingAdapterView_rotation_degrees, ROTATION_DEGREES);
71 | yOffsetStep = a.getDimensionPixelOffset(R.styleable.SwipeFlingAdapterView_y_offset_step, 0);
72 | a.recycle();
73 |
74 | }
75 |
76 | public void setIsNeedSwipe(boolean isNeedSwipe) {
77 | this.isNeedSwipe = isNeedSwipe;
78 | }
79 |
80 | /**
81 | * A shortcut method to set both the listeners and the adapter.
82 | *
83 | * @param context The activity context which extends onFlingListener, OnItemClickListener or both
84 | * @param mAdapter The adapter you have to set.
85 | */
86 | public void init(final Context context, Adapter mAdapter) {
87 | if(context instanceof onFlingListener) {
88 | mFlingListener = (onFlingListener) context;
89 | }else{
90 | throw new RuntimeException("Activity does not implement SwipeFlingAdapterView.onFlingListener");
91 | }
92 | if(context instanceof OnItemClickListener){
93 | mOnItemClickListener = (OnItemClickListener) context;
94 | }
95 | setAdapter(mAdapter);
96 | }
97 |
98 | @Override
99 | public View getSelectedView() {
100 | return mActiveCard;
101 | }
102 |
103 |
104 | @Override
105 | public void requestLayout() {
106 | if (!mInLayout) {
107 | super.requestLayout();
108 | }
109 | }
110 |
111 | @Override
112 | protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
113 | super.onLayout(changed, left, top, right, bottom);
114 | // if we don't have an adapter, we don't need to do anything
115 | if (mAdapter == null) {
116 | return;
117 | }
118 |
119 | mInLayout = true;
120 | final int adapterCount = mAdapter.getCount();
121 | if (adapterCount == 0) {
122 | // removeAllViewsInLayout();
123 | removeAndAddToCache(0);
124 | } else {
125 | View topCard = getChildAt(LAST_OBJECT_IN_STACK);
126 | if(mActiveCard != null && topCard != null && topCard == mActiveCard) {
127 | // removeViewsInLayout(0, LAST_OBJECT_IN_STACK);
128 | removeAndAddToCache(1);
129 | layoutChildren(1, adapterCount);
130 | }else{
131 | // Reset the UI and set top view listener
132 | // removeAllViewsInLayout();
133 | removeAndAddToCache(0);
134 | layoutChildren(0, adapterCount);
135 | setTopView();
136 | }
137 | }
138 | mInLayout = false;
139 |
140 | if (initTop == 0 && initLeft == 0 && mActiveCard != null) {
141 | initTop = mActiveCard.getTop();
142 | initLeft = mActiveCard.getLeft();
143 | }
144 |
145 | if(adapterCount < MIN_ADAPTER_STACK) {
146 | if(mFlingListener != null){
147 | mFlingListener.onAdapterAboutToEmpty(adapterCount);
148 | }
149 | }
150 | }
151 |
152 | private void removeAndAddToCache(int remain) {
153 | View view;
154 | for (int i = 0; i < getChildCount() - remain; ) {
155 | view = getChildAt(i);
156 | removeViewInLayout(view);
157 | cacheItems.add(view);
158 | }
159 | }
160 |
161 | private void layoutChildren(int startingIndex, int adapterCount){
162 | while (startingIndex < Math.min(adapterCount, MAX_VISIBLE) ) {
163 | View item = null;
164 | if (cacheItems.size() > 0) {
165 | item = cacheItems.get(0);
166 | cacheItems.remove(item);
167 | }
168 | View newUnderChild = mAdapter.getView(startingIndex, item, this);
169 | if (newUnderChild.getVisibility() != GONE) {
170 | makeAndAddView(newUnderChild, startingIndex);
171 | LAST_OBJECT_IN_STACK = startingIndex;
172 | }
173 | startingIndex++;
174 | }
175 | }
176 |
177 | @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
178 | private void makeAndAddView(View child, int index) {
179 |
180 | FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) child.getLayoutParams();
181 | addViewInLayout(child, 0, lp, true);
182 |
183 | final boolean needToMeasure = child.isLayoutRequested();
184 | if (needToMeasure) {
185 | int childWidthSpec = getChildMeasureSpec(getWidthMeasureSpec(),
186 | getPaddingLeft() + getPaddingRight() + lp.leftMargin + lp.rightMargin,
187 | lp.width);
188 | int childHeightSpec = getChildMeasureSpec(getHeightMeasureSpec(),
189 | getPaddingTop() + getPaddingBottom() + lp.topMargin + lp.bottomMargin,
190 | lp.height);
191 | child.measure(childWidthSpec, childHeightSpec);
192 | } else {
193 | cleanupLayoutState(child);
194 | }
195 |
196 | int w = child.getMeasuredWidth();
197 | int h = child.getMeasuredHeight();
198 |
199 | int gravity = lp.gravity;
200 | if (gravity == -1) {
201 | gravity = Gravity.TOP | Gravity.START;
202 | }
203 |
204 | int layoutDirection = 0;
205 | if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN)
206 | layoutDirection = getLayoutDirection();
207 | final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection);
208 | final int verticalGravity = gravity & Gravity.VERTICAL_GRAVITY_MASK;
209 |
210 | int childLeft;
211 | int childTop;
212 | switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
213 | case Gravity.CENTER_HORIZONTAL:
214 | childLeft = (getWidth() + getPaddingLeft() - getPaddingRight() - w) / 2 +
215 | lp.leftMargin - lp.rightMargin;
216 | break;
217 | case Gravity.END:
218 | childLeft = getWidth() + getPaddingRight() - w - lp.rightMargin;
219 | break;
220 | case Gravity.START:
221 | default:
222 | childLeft = getPaddingLeft() + lp.leftMargin;
223 | break;
224 | }
225 | switch (verticalGravity) {
226 | case Gravity.CENTER_VERTICAL:
227 | childTop = (getHeight() + getPaddingTop() - getPaddingBottom() - h) / 2 +
228 | lp.topMargin - lp.bottomMargin;
229 | break;
230 | case Gravity.BOTTOM:
231 | childTop = getHeight() - getPaddingBottom() - h - lp.bottomMargin;
232 | break;
233 | case Gravity.TOP:
234 | default:
235 | childTop = getPaddingTop() + lp.topMargin;
236 | break;
237 | }
238 | child.layout(childLeft, childTop, childLeft + w, childTop + h);
239 | // 缩放层叠效果
240 | adjustChildView(child, index);
241 | }
242 |
243 | private void adjustChildView(View child, int index) {
244 | if (index > -1 && index < MAX_VISIBLE) {
245 | int multiple;
246 | if (index > 2) multiple = 2;
247 | else multiple = index;
248 | child.offsetTopAndBottom(yOffsetStep * multiple);
249 | child.setScaleX(1 - SCALE_STEP * multiple);
250 | child.setScaleY(1 - SCALE_STEP * multiple);
251 | }
252 | }
253 |
254 | private void adjustChildrenOfUnderTopView(float scrollRate) {
255 | int count = getChildCount();
256 | if (count > 1) {
257 | int i;
258 | int multiple;
259 | if (count == 2) {
260 | i = LAST_OBJECT_IN_STACK - 1;
261 | multiple = 1;
262 | } else {
263 | i = LAST_OBJECT_IN_STACK - 2;
264 | multiple = 2;
265 | }
266 | float rate = Math.abs(scrollRate);
267 | for (; i < LAST_OBJECT_IN_STACK; i++, multiple--) {
268 | View underTopView = getChildAt(i);
269 | int offset = (int) (yOffsetStep * (multiple - rate));
270 | underTopView.offsetTopAndBottom(offset - underTopView.getTop() + initTop);
271 | underTopView.setScaleX(1 - SCALE_STEP * multiple + SCALE_STEP * rate);
272 | underTopView.setScaleY(1 - SCALE_STEP * multiple + SCALE_STEP * rate);
273 | }
274 | }
275 | }
276 |
277 | /**
278 | * Set the top view and add the fling listener
279 | */
280 | private void setTopView() {
281 | if(getChildCount()>0){
282 |
283 | mActiveCard = getChildAt(LAST_OBJECT_IN_STACK);
284 | if(mActiveCard != null && mFlingListener != null) {
285 |
286 | flingCardListener = new FlingCardListener(mActiveCard, mAdapter.getItem(0),
287 | ROTATION_DEGREES, new FlingCardListener.FlingListener() {
288 |
289 | @Override
290 | public void onCardExited() {
291 | removeViewInLayout(mActiveCard);
292 | mActiveCard = null;
293 | mFlingListener.removeFirstObjectInAdapter();
294 | }
295 |
296 | @Override
297 | public void leftExit(Object dataObject) {
298 | mFlingListener.onLeftCardExit(dataObject);
299 | }
300 |
301 | @Override
302 | public void rightExit(Object dataObject) {
303 | mFlingListener.onRightCardExit(dataObject);
304 | }
305 |
306 | @Override
307 | public void onClick(MotionEvent event, View v, Object dataObject) {
308 | if(mOnItemClickListener != null)
309 | mOnItemClickListener.onItemClicked(event, v, dataObject);
310 | }
311 |
312 | @Override
313 | public void onScroll(float progress, float scrollXProgress) {
314 | // Log.e("Log", "onScroll " + progress);
315 | adjustChildrenOfUnderTopView(progress);
316 | mFlingListener.onScroll(progress, scrollXProgress);
317 | }
318 | });
319 | // 设置是否支持左右滑
320 | flingCardListener.setIsNeedSwipe(isNeedSwipe);
321 |
322 | mActiveCard.setOnTouchListener(flingCardListener);
323 | }
324 | }
325 | }
326 |
327 | public FlingCardListener getTopCardListener() throws NullPointerException {
328 | if(flingCardListener==null){
329 | throw new NullPointerException("flingCardListener is null");
330 | }
331 | return flingCardListener;
332 | }
333 |
334 | public void setMaxVisible(int MAX_VISIBLE){
335 | this.MAX_VISIBLE = MAX_VISIBLE;
336 | }
337 |
338 | public void setMinStackInAdapter(int MIN_ADAPTER_STACK) {
339 | this.MIN_ADAPTER_STACK = MIN_ADAPTER_STACK;
340 | }
341 |
342 | /**
343 | * click to swipe left
344 | */
345 | public void swipeLeft() {
346 | getTopCardListener().selectLeft();
347 | }
348 |
349 | public void swipeLeft(int duration) {
350 | getTopCardListener().selectLeft(duration);
351 | }
352 |
353 | /**
354 | * click to swipe right
355 | */
356 | public void swipeRight() {
357 | getTopCardListener().selectRight();
358 | }
359 |
360 | public void swipeRight(int duration) {
361 | getTopCardListener().selectRight(duration);
362 | }
363 |
364 | @Override
365 | public Adapter getAdapter() {
366 | return mAdapter;
367 | }
368 |
369 |
370 | @Override
371 | public void setAdapter(Adapter adapter) {
372 | if (mAdapter != null && mDataSetObserver != null) {
373 | mAdapter.unregisterDataSetObserver(mDataSetObserver);
374 | mDataSetObserver = null;
375 | }
376 |
377 | mAdapter = adapter;
378 |
379 | if (mAdapter != null && mDataSetObserver == null) {
380 | mDataSetObserver = new AdapterDataSetObserver();
381 | mAdapter.registerDataSetObserver(mDataSetObserver);
382 | }
383 | }
384 |
385 | public void setFlingListener(onFlingListener onFlingListener) {
386 | this.mFlingListener = onFlingListener;
387 | }
388 |
389 | public void setOnItemClickListener(OnItemClickListener onItemClickListener){
390 | this.mOnItemClickListener = onItemClickListener;
391 | }
392 |
393 |
394 | @Override
395 | public LayoutParams generateLayoutParams(AttributeSet attrs) {
396 | return new FrameLayout.LayoutParams(getContext(), attrs);
397 | }
398 |
399 |
400 | private class AdapterDataSetObserver extends DataSetObserver {
401 | @Override
402 | public void onChanged() {
403 | requestLayout();
404 | }
405 |
406 | @Override
407 | public void onInvalidated() {
408 | requestLayout();
409 | }
410 |
411 | }
412 |
413 |
414 | public interface OnItemClickListener {
415 | void onItemClicked(MotionEvent event, View v, Object dataObject);
416 | }
417 |
418 | public interface onFlingListener {
419 | void removeFirstObjectInAdapter();
420 | void onLeftCardExit(Object dataObject);
421 | void onRightCardExit(Object dataObject);
422 | void onAdapterAboutToEmpty(int itemsInAdapter);
423 | void onScroll(float progress, float scrollXProgress);
424 | }
425 |
426 |
427 | }
428 |
--------------------------------------------------------------------------------
/app/src/main/java/me/payge/swipecardview/MainActivity.java:
--------------------------------------------------------------------------------
1 | package me.payge.swipecardview;
2 |
3 | import android.os.AsyncTask;
4 | import android.os.Bundle;
5 | import android.support.v7.app.AppCompatActivity;
6 | import android.util.DisplayMetrics;
7 | import android.view.LayoutInflater;
8 | import android.view.MotionEvent;
9 | import android.view.View;
10 | import android.view.ViewGroup;
11 | import android.widget.BaseAdapter;
12 | import android.widget.CheckedTextView;
13 | import android.widget.ImageView;
14 | import android.widget.TextView;
15 |
16 | import com.lorentzos.flingswipe.SwipeFlingAdapterView;
17 |
18 | import java.util.ArrayList;
19 | import java.util.Collection;
20 | import java.util.List;
21 | import java.util.Random;
22 |
23 | public class MainActivity extends AppCompatActivity implements SwipeFlingAdapterView.onFlingListener,
24 | SwipeFlingAdapterView.OnItemClickListener, View.OnClickListener {
25 |
26 | int [] headerIcons = {
27 | R.drawable.i1,
28 | R.drawable.i2,
29 | R.drawable.i3,
30 | R.drawable.i4,
31 | R.drawable.i5,
32 | R.drawable.i6
33 | };
34 |
35 | String [] names = {"张三","李四","王五","小明","小红","小花"};
36 |
37 | String [] citys = {"北京", "上海", "广州", "深圳"};
38 |
39 | String [] edus = {"大专", "本科", "硕士", "博士"};
40 |
41 | String [] years = {"1年", "2年", "3年", "4年", "5年"};
42 |
43 | Random ran = new Random();
44 |
45 | private int cardWidth;
46 | private int cardHeight;
47 |
48 | private SwipeFlingAdapterView swipeView;
49 | private InnerAdapter adapter;
50 |
51 |
52 | @Override
53 | protected void onCreate(Bundle savedInstanceState) {
54 | super.onCreate(savedInstanceState);
55 | setContentView(R.layout.activity_main);
56 |
57 | initView();
58 | loadData();
59 | }
60 |
61 | private void initView() {
62 | DisplayMetrics dm = getResources().getDisplayMetrics();
63 | float density = dm.density;
64 | cardWidth = (int) (dm.widthPixels - (2 * 18 * density));
65 | cardHeight = (int) (dm.heightPixels - (338 * density));
66 |
67 |
68 | swipeView = (SwipeFlingAdapterView) findViewById(R.id.swipe_view);
69 | if (swipeView != null) {
70 | swipeView.setIsNeedSwipe(true);
71 | swipeView.setFlingListener(this);
72 | swipeView.setOnItemClickListener(this);
73 |
74 | adapter = new InnerAdapter();
75 | swipeView.setAdapter(adapter);
76 | }
77 |
78 | View v = findViewById(R.id.swipeLeft);
79 | if (v != null) {
80 | v.setOnClickListener(this);
81 | }
82 | v = findViewById(R.id.swipeRight);
83 | if (v != null) {
84 | v.setOnClickListener(this);
85 | }
86 |
87 | }
88 |
89 |
90 | @Override
91 | public void onItemClicked(MotionEvent event, View v, Object dataObject) {
92 | }
93 |
94 | @Override
95 | public void removeFirstObjectInAdapter() {
96 | adapter.remove(0);
97 | }
98 |
99 | @Override
100 | public void onLeftCardExit(Object dataObject) {
101 | }
102 |
103 | @Override
104 | public void onRightCardExit(Object dataObject) {
105 | }
106 |
107 | @Override
108 | public void onAdapterAboutToEmpty(int itemsInAdapter) {
109 | if (itemsInAdapter == 3) {
110 | loadData();
111 | }
112 | }
113 |
114 | @Override
115 | public void onScroll(float progress, float scrollXProgress) {
116 | }
117 |
118 | @Override
119 | public void onClick(View v) {
120 | switch (v.getId()) {
121 | case R.id.swipeLeft:
122 | swipeView.swipeLeft();
123 | //swipeView.swipeLeft(250);
124 | break;
125 | case R.id.swipeRight:
126 | swipeView.swipeRight();
127 | //swipeView.swipeRight(250);
128 | }
129 | }
130 |
131 | private void loadData() {
132 | new AsyncTask>() {
133 | @Override
134 | protected List doInBackground(Void... params) {
135 | ArrayList list = new ArrayList<>(10);
136 | Talent talent;
137 | for (int i = 0; i < 10; i++) {
138 | talent = new Talent();
139 | talent.headerIcon = headerIcons[i % headerIcons.length];
140 | talent.nickname = names[ran.nextInt(names.length-1)];
141 | talent.cityName = citys[ran.nextInt(citys.length-1)];
142 | talent.educationName = edus[ran.nextInt(edus.length-1)];
143 | talent.workYearName = years[ran.nextInt(years.length-1)];
144 | list.add(talent);
145 | }
146 | return list;
147 | }
148 |
149 | @Override
150 | protected void onPostExecute(List list) {
151 | super.onPostExecute(list);
152 | adapter.addAll(list);
153 | }
154 | }.execute();
155 | }
156 |
157 |
158 | private class InnerAdapter extends BaseAdapter {
159 |
160 | ArrayList objs;
161 |
162 | public InnerAdapter() {
163 | objs = new ArrayList<>();
164 | }
165 |
166 | public void addAll(Collection collection) {
167 | if (isEmpty()) {
168 | objs.addAll(collection);
169 | notifyDataSetChanged();
170 | } else {
171 | objs.addAll(collection);
172 | }
173 | }
174 |
175 | public void clear() {
176 | objs.clear();
177 | notifyDataSetChanged();
178 | }
179 |
180 | public boolean isEmpty() {
181 | return objs.isEmpty();
182 | }
183 |
184 | public void remove(int index) {
185 | if (index > -1 && index < objs.size()) {
186 | objs.remove(index);
187 | notifyDataSetChanged();
188 | }
189 | }
190 |
191 |
192 | @Override
193 | public int getCount() {
194 | return objs.size();
195 | }
196 |
197 | @Override
198 | public Talent getItem(int position) {
199 | if(objs==null ||objs.size()==0) return null;
200 | return objs.get(position);
201 | }
202 |
203 | @Override
204 | public long getItemId(int position) {
205 | return position;
206 | }
207 |
208 | // TODO: getView
209 | @Override
210 | public View getView(int position, View convertView, ViewGroup parent) {
211 | ViewHolder holder;
212 | Talent talent = getItem(position);
213 | if (convertView == null) {
214 | convertView = LayoutInflater.from(parent.getContext()).inflate(R.layout.card_new_item, parent, false);
215 | holder = new ViewHolder();
216 | convertView.setTag(holder);
217 | convertView.getLayoutParams().width = cardWidth;
218 | holder.portraitView = (ImageView) convertView.findViewById(R.id.portrait);
219 | //holder.portraitView.getLayoutParams().width = cardWidth;
220 | holder.portraitView.getLayoutParams().height = cardHeight;
221 | holder.nameView = (TextView) convertView.findViewById(R.id.name);
222 | //parentView.getLayoutParams().width = cardWidth;
223 | //holder.jobView = (TextView) convertView.findViewById(R.id.job);
224 | //holder.companyView = (TextView) convertView.findViewById(R.id.company);
225 | holder.cityView = (TextView) convertView.findViewById(R.id.city);
226 | holder.eduView = (TextView) convertView.findViewById(R.id.education);
227 | holder.workView = (TextView) convertView.findViewById(R.id.work_year);
228 | } else {
229 | holder = (ViewHolder) convertView.getTag();
230 | }
231 |
232 |
233 | holder.portraitView.setImageResource(talent.headerIcon);
234 |
235 | holder.nameView.setText(String.format("%s", talent.nickname));
236 | //holder.jobView.setText(talent.jobName);
237 |
238 | final CharSequence no = "暂无";
239 |
240 | holder.cityView.setHint(no);
241 | holder.cityView.setText(talent.cityName);
242 | holder.cityView.setCompoundDrawablesWithIntrinsicBounds(0,R.drawable.home01_icon_location,0,0);
243 |
244 | holder.eduView.setHint(no);
245 | holder.eduView.setText(talent.educationName);
246 | holder.eduView.setCompoundDrawablesWithIntrinsicBounds(0,R.drawable.home01_icon_edu,0,0);
247 |
248 | holder.workView.setHint(no);
249 | holder.workView.setText(talent.workYearName);
250 | holder.workView.setCompoundDrawablesWithIntrinsicBounds(0,R.drawable.home01_icon_work_year,0,0);
251 |
252 |
253 | return convertView;
254 | }
255 |
256 | }
257 |
258 | private static class ViewHolder {
259 | ImageView portraitView;
260 | TextView nameView;
261 | TextView cityView;
262 | TextView eduView;
263 | TextView workView;
264 | CheckedTextView collectView;
265 |
266 | }
267 |
268 | public static class Talent {
269 | public int headerIcon;
270 | public String nickname;
271 | public String cityName;
272 | public String educationName;
273 | public String workYearName;
274 | }
275 |
276 | }
277 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/default_card.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiepeijie/SwipeCardView/b8caed6296fd1ff1547cf022e62c45b71c0ee11b/app/src/main/res/drawable-xxhdpi/default_card.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/home01_bg_card.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiepeijie/SwipeCardView/b8caed6296fd1ff1547cf022e62c45b71c0ee11b/app/src/main/res/drawable-xxhdpi/home01_bg_card.9.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/home01_btn_collect.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiepeijie/SwipeCardView/b8caed6296fd1ff1547cf022e62c45b71c0ee11b/app/src/main/res/drawable-xxhdpi/home01_btn_collect.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/home01_icon_edu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiepeijie/SwipeCardView/b8caed6296fd1ff1547cf022e62c45b71c0ee11b/app/src/main/res/drawable-xxhdpi/home01_icon_edu.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/home01_icon_location.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiepeijie/SwipeCardView/b8caed6296fd1ff1547cf022e62c45b71c0ee11b/app/src/main/res/drawable-xxhdpi/home01_icon_location.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/home01_icon_work_year.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiepeijie/SwipeCardView/b8caed6296fd1ff1547cf022e62c45b71c0ee11b/app/src/main/res/drawable-xxhdpi/home01_icon_work_year.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/i1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiepeijie/SwipeCardView/b8caed6296fd1ff1547cf022e62c45b71c0ee11b/app/src/main/res/drawable-xxhdpi/i1.jpg
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/i2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiepeijie/SwipeCardView/b8caed6296fd1ff1547cf022e62c45b71c0ee11b/app/src/main/res/drawable-xxhdpi/i2.jpg
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/i3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiepeijie/SwipeCardView/b8caed6296fd1ff1547cf022e62c45b71c0ee11b/app/src/main/res/drawable-xxhdpi/i3.jpg
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/i4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiepeijie/SwipeCardView/b8caed6296fd1ff1547cf022e62c45b71c0ee11b/app/src/main/res/drawable-xxhdpi/i4.jpg
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/i5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiepeijie/SwipeCardView/b8caed6296fd1ff1547cf022e62c45b71c0ee11b/app/src/main/res/drawable-xxhdpi/i5.jpg
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/i6.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiepeijie/SwipeCardView/b8caed6296fd1ff1547cf022e62c45b71c0ee11b/app/src/main/res/drawable-xxhdpi/i6.jpg
--------------------------------------------------------------------------------
/app/src/main/res/drawable/bg_button.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 |
7 |
8 |
9 |
10 | -
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
15 |
22 |
32 |
42 |
43 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/card_new_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
18 |
19 |
26 |
27 |
36 |
37 |
50 |
60 |
70 |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiepeijie/SwipeCardView/b8caed6296fd1ff1547cf022e62c45b71c0ee11b/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiepeijie/SwipeCardView/b8caed6296fd1ff1547cf022e62c45b71c0ee11b/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiepeijie/SwipeCardView/b8caed6296fd1ff1547cf022e62c45b71c0ee11b/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiepeijie/SwipeCardView/b8caed6296fd1ff1547cf022e62c45b71c0ee11b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiepeijie/SwipeCardView/b8caed6296fd1ff1547cf022e62c45b71c0ee11b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | SwipeCardView
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/values/swipe_fling_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/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.0'
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 |
--------------------------------------------------------------------------------
/ezgif.com.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiepeijie/SwipeCardView/b8caed6296fd1ff1547cf022e62c45b71c0ee11b/ezgif.com.gif
--------------------------------------------------------------------------------
/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 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiepeijie/SwipeCardView/b8caed6296fd1ff1547cf022e62c45b71c0ee11b/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Mon Dec 28 10:00:20 PST 2015
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'
2 |
--------------------------------------------------------------------------------