├── .gitignore
├── FlipShare
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── me
│ │ └── wangyuwei
│ │ └── flipshare
│ │ └── ApplicationTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ └── java
│ │ └── me
│ │ └── wangyuwei
│ │ └── flipshare
│ │ ├── FlipShareView.java
│ │ └── ShareItem.java
│ └── test
│ └── java
│ └── me
│ └── wangyuwei
│ └── flipshare
│ └── ExampleUnitTest.java
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── me
│ │ └── wangyuwei
│ │ └── flipshare
│ │ └── ApplicationTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── me
│ │ │ └── wangyuwei
│ │ │ └── flipshare
│ │ │ └── MainActivity.java
│ └── res
│ │ ├── layout
│ │ └── activity_main.xml
│ │ ├── mipmap-hdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-mdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xhdpi
│ │ ├── ic_facebook.png
│ │ ├── ic_google.png
│ │ ├── ic_launcher.png
│ │ └── ic_twitter.png
│ │ ├── mipmap-xxhdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xxxhdpi
│ │ └── ic_launcher.png
│ │ ├── values-w820dp
│ │ └── dimens.xml
│ │ └── values
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── me
│ └── wangyuwei
│ └── flipshare
│ └── ExampleUnitTest.java
├── build.gradle
├── checkstyle.xml
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── screenshots
└── flipshare.gif
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea
5 | .DS_Store
6 | /build
7 | /captures
8 |
--------------------------------------------------------------------------------
/FlipShare/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/FlipShare/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply plugin: 'com.jfrog.bintray'
3 | apply plugin: 'com.github.dcendents.android-maven'
4 |
5 | group = 'me.wangyuwei' // Change this to match your package name
6 | version = '1.0.2' // Change this to match your version number
7 |
8 | android {
9 | compileSdkVersion 23
10 | buildToolsVersion "23.0.1"
11 |
12 | defaultConfig {
13 | minSdkVersion 15
14 | targetSdkVersion 23
15 | versionCode 1
16 | versionName "1.0"
17 | }
18 | buildTypes {
19 | release {
20 | minifyEnabled false
21 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
22 | }
23 | }
24 | }
25 |
26 | dependencies {
27 | compile fileTree(dir: 'libs', include: ['*.jar'])
28 | testCompile 'junit:junit:4.12'
29 | compile 'com.android.support:appcompat-v7:23.1.1'
30 | }
31 |
32 | task generateSourcesJar(type: Jar) {
33 | from android.sourceSets.main.java.srcDirs
34 | classifier 'sources'
35 | }
36 |
37 | task generateJavadocs(type: Javadoc) {
38 | source = android.sourceSets.main.java.srcDirs
39 | classpath += project.files(android.getBootClasspath()
40 | .join(File.pathSeparator))
41 | }
42 |
43 | task generateJavadocsJar(type: Jar) {
44 | from generateJavadocs.destinationDir
45 | classifier 'javadoc'
46 | }
47 |
48 | artifacts {
49 | // archives generateJavaDocsJar
50 | archives generateSourcesJar
51 | }
52 |
53 | Properties properties = new Properties()
54 | properties.load(project.rootProject.file('local.properties').newDataInputStream())
55 | bintray {
56 | user = properties.getProperty("bintray.user")
57 | key = properties.getProperty("bintray.key")
58 | pkg {
59 | repo = 'maven'
60 | name = 'FlipShare'
61 | desc = "It's a cool way to show share widget."
62 |
63 | version {
64 | name = '1.0.2'
65 | desc = 'It is a cool way to show share widget.'
66 | vcsTag = 'android, animation, view, splash'
67 | }
68 |
69 | licenses = ['Apache-2.0']
70 | vcsUrl = 'https://github.com/JeasonWong/FlipShare.git'
71 | websiteUrl = 'https://github.com/JeasonWong/FlipShare'
72 |
73 | labels = ['android']
74 | publish = true
75 | publicDownloadNumbers = true
76 | }
77 | configurations = ['archives']
78 | }
--------------------------------------------------------------------------------
/FlipShare/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 /Users/wscn/Documents/android-sdk-macosx/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 |
--------------------------------------------------------------------------------
/FlipShare/src/androidTest/java/me/wangyuwei/flipshare/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package me.wangyuwei.flipshare;
2 |
3 | import android.app.Application;
4 | import android.test.ApplicationTestCase;
5 |
6 | /**
7 | * Testing Fundamentals
8 | */
9 | public class ApplicationTest extends ApplicationTestCase {
10 | public ApplicationTest() {
11 | super(Application.class);
12 | }
13 | }
--------------------------------------------------------------------------------
/FlipShare/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/FlipShare/src/main/java/me/wangyuwei/flipshare/FlipShareView.java:
--------------------------------------------------------------------------------
1 | package me.wangyuwei.flipshare;
2 |
3 | import android.animation.Animator;
4 | import android.animation.AnimatorSet;
5 | import android.animation.ObjectAnimator;
6 | import android.animation.ValueAnimator;
7 | import android.app.Activity;
8 | import android.content.Context;
9 | import android.graphics.Camera;
10 | import android.graphics.Canvas;
11 | import android.graphics.Color;
12 | import android.graphics.Matrix;
13 | import android.graphics.Paint;
14 | import android.graphics.Path;
15 | import android.graphics.PointF;
16 | import android.graphics.Rect;
17 | import android.graphics.RectF;
18 | import android.support.annotation.IntDef;
19 | import android.text.TextUtils;
20 | import android.view.MotionEvent;
21 | import android.view.View;
22 | import android.view.ViewGroup;
23 | import android.view.Window;
24 | import android.view.WindowManager;
25 | import android.view.animation.LinearInterpolator;
26 |
27 | import java.util.ArrayList;
28 | import java.util.Collection;
29 | import java.util.List;
30 |
31 | /**
32 | * 作者: 巴掌 on 16/9/1 21:38
33 | * Github: https://github.com/JeasonWong
34 | */
35 | public class FlipShareView extends View {
36 |
37 | private static final int STATUS_NONE = 0;
38 | private static final int STATUS_DOWN = 1;
39 | private static final int STATUS_UP = 2;
40 |
41 | public static final int TYPE_VERTICLE = 0;
42 | public static final int TYPE_HORIZONTAL = 1;
43 | public static final int TYPE_SLIDE = 1 << 1;
44 |
45 | private int mStatus = STATUS_NONE;
46 |
47 | private Paint mPaint;
48 | private Path mPath;
49 | private Camera mCamera;
50 | private Matrix mMatrix;
51 | //item's flip degree
52 | private float mDegree;
53 | //item's shake degree
54 | private float mItemShakeDegree;
55 | //current item which is showing
56 | private int mCurrentItem = 0;
57 | //everyItem's animation duration
58 | private int mDuration = 300;
59 | //total window view's background color
60 | private int mBackgroundColor = 0x00FFFFFF;
61 | //separate line's color
62 | private int mSeparateLineColor = Color.TRANSPARENT;
63 | //separate line's height
64 | private int mSeparateLineHeight = dip2px(0.4f);
65 | //background color area
66 | private RectF mBgRect;
67 | //shareItem's width
68 | private int mItemWidth = dip2px(140);
69 | //shareItem's height
70 | private int mItemHeight = dip2px(50);
71 | //shareItem's left x position
72 | private int mItemLeft = dip2px(0);
73 | //shareItem's top y position
74 | private int mItemTop = dip2px(50);
75 | //item's corner
76 | private int mCorner = dip2px(6);
77 | //triangle's height
78 | private int mTriangleHeight = dip2px(4);
79 | //border's margin
80 | private int mBorderMargin = dip2px(5);
81 | //the first shown item's top y coordinate
82 | private int mFirstItemTop;
83 | //screen width
84 | private int mScreenWidth;
85 | //screen height
86 | private int mScreenHeight;
87 | //parent view is used to position
88 | private View mParentView;
89 | //shareItem lists
90 | private List mItemList = new ArrayList<>();
91 | private List mItemRectList = new ArrayList<>();
92 |
93 | private int mAnimType = TYPE_VERTICLE;
94 | private final List mTotalAnimList = new ArrayList<>();
95 | private ObjectAnimator mAlphaAnim;
96 |
97 | private OnFlipClickListener onFlipClickListener;
98 |
99 | public FlipShareView(Context context, Window window, View parentView) {
100 | super(context);
101 | mParentView = parentView;
102 | mScreenWidth = getResources().getDisplayMetrics().widthPixels;
103 | mScreenHeight = getResources().getDisplayMetrics().heightPixels;
104 | mBgRect = new RectF(0, 0, mScreenWidth, mScreenHeight);
105 | addView(window);
106 | initView();
107 | }
108 |
109 | private void addView(Window window) {
110 | WindowManager.LayoutParams params = new WindowManager.LayoutParams(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT);
111 | window.addContentView(this, params);
112 | }
113 |
114 | private void initView() {
115 | mPath = new Path();
116 | mPaint = new Paint();
117 | mPaint.setAntiAlias(true);
118 | mPaint.setStyle(Paint.Style.FILL);
119 | mPaint.setTextSize(sp2px(14));
120 | mCamera = new Camera();
121 | mMatrix = new Matrix();
122 |
123 | mAlphaAnim = ObjectAnimator.ofFloat(this, "alpha", 1.0f, 0f);
124 | mAlphaAnim.setDuration(200);
125 | mAlphaAnim.addListener(new MyAnimListener() {
126 | @Override
127 | public void onAnimationEnd(Animator animation) {
128 | removeView();
129 | if (onFlipClickListener != null) {
130 | onFlipClickListener.dismiss();
131 | }
132 | }
133 | });
134 |
135 | int parentViewWidth = mParentView.getMeasuredWidth();
136 | int parentViewHeight = mParentView.getMeasuredHeight();
137 | int parentLeft = mParentView.getLeft();
138 | int[] location = new int[2];
139 | mParentView.getLocationInWindow(location);
140 | int parentTop = location[1] - parentViewHeight / 2;
141 | int parentBottom = location[1] + parentViewHeight / 2;
142 | int parentMiddleX = parentLeft + parentViewWidth / 2;
143 |
144 | if (location[1] < mScreenHeight / 2) {
145 | mStatus = STATUS_DOWN;
146 | mItemTop = parentBottom + dip2px(5);
147 | mFirstItemTop = mItemTop + dip2px(6);
148 | } else {
149 | mStatus = STATUS_UP;
150 | mItemTop = parentTop - dip2px(5);
151 | mFirstItemTop = mItemTop - dip2px(6);
152 | }
153 |
154 | if (parentMiddleX + mItemWidth / 2 > mScreenWidth) {
155 | mItemLeft = mScreenWidth - mItemWidth - mBorderMargin;
156 | } else if (parentMiddleX - mItemWidth / 2 < 0) {
157 | mItemLeft = mBorderMargin;
158 | } else {
159 | mItemLeft = parentMiddleX - mItemWidth / 2;
160 | }
161 |
162 |
163 | }
164 |
165 | @Override
166 | protected void onDraw(Canvas canvas) {
167 | super.onDraw(canvas);
168 | switch (mStatus) {
169 | case STATUS_NONE:
170 |
171 | break;
172 | case STATUS_DOWN:
173 | drawBackground(canvas);
174 | drawFlipDownItem(canvas);
175 | break;
176 | case STATUS_UP:
177 | drawBackground(canvas);
178 | drawFlipUpItem(canvas);
179 | break;
180 | }
181 |
182 | }
183 |
184 | private void drawBackground(Canvas canvas) {
185 | mPaint.setColor(mBackgroundColor);
186 | canvas.drawRect(mBgRect, mPaint);
187 | }
188 |
189 | private void drawFlipUpItem(Canvas canvas) {
190 | mItemRectList.clear();
191 |
192 | for (int i = mItemList.size() - 1; i >= 0; i--) {
193 | canvas.save();
194 | mCamera.save();
195 |
196 | if (i < mItemList.size() - mCurrentItem - 1) {
197 | mCamera.restore();
198 | canvas.restore();
199 | continue;
200 | } else {
201 | if (i == mItemList.size() - mCurrentItem - 1) {
202 | if (mAnimType == TYPE_HORIZONTAL) {
203 | mCamera.rotateY(mDegree);
204 | } else if (mAnimType == TYPE_VERTICLE) {
205 | mCamera.rotateX(mDegree);
206 | } else if (mAnimType == TYPE_SLIDE) {
207 | mCamera.rotateZ(mDegree);
208 | }
209 | } else {
210 | if (mAnimType == TYPE_HORIZONTAL) {
211 | mCamera.rotateY(mItemShakeDegree / 2);
212 | } else if (mAnimType == TYPE_VERTICLE) {
213 | mCamera.rotateX(mItemShakeDegree);
214 | } else if (mAnimType == TYPE_SLIDE) {
215 | mCamera.rotateZ(mItemShakeDegree / 4);
216 | }
217 | }
218 | mCamera.getMatrix(mMatrix);
219 | if (mAnimType == TYPE_SLIDE) {
220 | mMatrix.preTranslate(-(mItemLeft + mItemWidth / 2), -mItemHeight / 2);
221 | mMatrix.postTranslate(mItemLeft + mItemWidth / 2, mItemHeight / 2);
222 | } else {
223 | mMatrix.preTranslate(-(mItemLeft + mItemWidth / 2), -(mItemTop - (mItemList.size() - i - 1) * mItemHeight));
224 | mMatrix.postTranslate(mItemLeft + mItemWidth / 2, mItemTop - (mItemList.size() - i - 1) * mItemHeight);
225 | }
226 |
227 | canvas.concat(mMatrix);
228 | }
229 |
230 | mPaint.setColor(mItemList.get(i).bgColor);
231 | if (i == mItemList.size() - 1) {
232 | mPath.reset();
233 | int parentMiddleX = mParentView.getLeft() + mParentView.getMeasuredWidth() / 2;
234 | mPath.moveTo(parentMiddleX, mItemTop);
235 | mPath.lineTo(parentMiddleX - mTriangleHeight, mFirstItemTop);
236 | mPath.lineTo(parentMiddleX + mTriangleHeight, mFirstItemTop);
237 | canvas.drawPath(mPath, mPaint);
238 | }
239 |
240 | if (i == 0) {
241 | mPath.reset();
242 | mPath.moveTo(mItemLeft, mFirstItemTop - (mItemList.size() - 1) * mItemHeight);
243 | mPath.lineTo(mItemLeft + mItemWidth, mFirstItemTop - (mItemList.size() - 1) * mItemHeight);
244 | mPath.lineTo(mItemLeft + mItemWidth, mFirstItemTop - (mItemList.size() - 1) * mItemHeight - mItemHeight + mCorner);
245 | mPath.quadTo(mItemLeft + mItemWidth, mFirstItemTop - (mItemList.size() - 1) * mItemHeight - mItemHeight
246 | , mItemLeft + mItemWidth - mCorner, mFirstItemTop - (mItemList.size() - 1) * mItemHeight - mItemHeight);
247 | mPath.lineTo(mItemLeft + mCorner, mFirstItemTop - (mItemList.size() - 1) * mItemHeight - mItemHeight);
248 | mPath.quadTo(mItemLeft, mFirstItemTop - (mItemList.size() - 1) * mItemHeight - mItemHeight
249 | , mItemLeft, mFirstItemTop - (mItemList.size() - 1) * mItemHeight - mItemHeight + mCorner);
250 | mPath.lineTo(mItemLeft, mFirstItemTop - (mItemList.size() - 1) * mItemHeight);
251 | canvas.drawPath(mPath, mPaint);
252 | mPaint.setColor(mSeparateLineColor);
253 | canvas.drawLine(mItemLeft, mFirstItemTop - (mItemList.size() - 1) * mItemHeight - mSeparateLineHeight
254 | , mItemLeft + mItemWidth, mFirstItemTop - (mItemList.size() - 1) * mItemHeight - mSeparateLineHeight, mPaint);
255 | } else if (i == mItemList.size() - 1) {
256 | mPath.reset();
257 | mPath.moveTo(mItemLeft, mFirstItemTop - (mItemList.size() - i) * mItemHeight);
258 | mPath.lineTo(mItemLeft + mItemWidth, mFirstItemTop - (mItemList.size() - i) * mItemHeight);
259 | mPath.lineTo(mItemLeft + mItemWidth, mFirstItemTop - (mItemList.size() - i) * mItemHeight + mItemHeight - mCorner);
260 | mPath.quadTo(mItemLeft + mItemWidth, mFirstItemTop - (mItemList.size() - i) * mItemHeight + mItemHeight
261 | , mItemLeft + mItemWidth - mCorner, mFirstItemTop - (mItemList.size() - i) * mItemHeight + mItemHeight);
262 | mPath.lineTo(mItemLeft + mCorner, mFirstItemTop - (mItemList.size() - i) * mItemHeight + mItemHeight);
263 | mPath.quadTo(mItemLeft, mFirstItemTop - (mItemList.size() - i) * mItemHeight + mItemHeight
264 | , mItemLeft, mFirstItemTop - (mItemList.size() - i) * mItemHeight + mItemHeight - mCorner);
265 | mPath.lineTo(mItemLeft, mFirstItemTop - (mItemList.size() - i) * mItemHeight);
266 | canvas.drawPath(mPath, mPaint);
267 | } else {
268 | canvas.drawRect(mItemLeft, mFirstItemTop - mItemHeight - (mItemList.size() - i - 1) * mItemHeight
269 | , mItemLeft + mItemWidth, mFirstItemTop - (mItemList.size() - i - 1) * mItemHeight, mPaint);
270 | mPaint.setColor(mSeparateLineColor);
271 | canvas.drawLine(mItemLeft, mFirstItemTop - (mItemList.size() - i - 1) * mItemHeight - mSeparateLineHeight
272 | , mItemLeft + mItemWidth, mFirstItemTop - (mItemList.size() - i - 1) * mItemHeight - mSeparateLineHeight, mPaint);
273 | }
274 |
275 | mItemRectList.add(new RectF(mItemLeft, (mFirstItemTop - mItemHeight) - i * mItemHeight, mItemLeft + mItemWidth,mFirstItemTop - i * mItemHeight));
276 |
277 | drawTitle(canvas, i);
278 | drawIcon(canvas, i);
279 |
280 | mCamera.restore();
281 | canvas.restore();
282 | }
283 |
284 | }
285 |
286 | private void drawFlipDownItem(Canvas canvas) {
287 |
288 | mItemRectList.clear();
289 | for (int i = 0; i < mItemList.size(); i++) {
290 | canvas.save();
291 | mCamera.save();
292 |
293 | if (i > mCurrentItem) {
294 | mCamera.restore();
295 | canvas.restore();
296 | continue;
297 | } else {
298 | if (i == mCurrentItem) {
299 | if (mAnimType == TYPE_HORIZONTAL) {
300 | mCamera.rotateY(mDegree);
301 | } else if (mAnimType == TYPE_VERTICLE) {
302 | mCamera.rotateX(mDegree);
303 | } else if (mAnimType == TYPE_SLIDE) {
304 | mCamera.rotateZ(mDegree);
305 | }
306 | } else {
307 | if (mAnimType == TYPE_HORIZONTAL) {
308 | mCamera.rotateY(mItemShakeDegree / 2);
309 | } else if (mAnimType == TYPE_VERTICLE) {
310 | mCamera.rotateX(mItemShakeDegree);
311 | } else if (mAnimType == TYPE_SLIDE) {
312 | mCamera.rotateZ(mItemShakeDegree);
313 | }
314 | }
315 | mCamera.getMatrix(mMatrix);
316 | if (mAnimType == TYPE_SLIDE) {
317 | mMatrix.preTranslate(-(mItemLeft + mItemWidth / 2), -mItemHeight / 2);
318 | mMatrix.postTranslate(mItemLeft + mItemWidth / 2, mItemHeight / 2);
319 | } else {
320 | mMatrix.preTranslate(-(mItemLeft + mItemWidth / 2), -(mItemTop + i * mItemHeight));
321 | mMatrix.postTranslate(mItemLeft + mItemWidth / 2, mItemTop + i * mItemHeight);
322 | }
323 | canvas.concat(mMatrix);
324 | }
325 |
326 | mPaint.setColor(mItemList.get(i).bgColor);
327 | if (i == 0) {
328 | mPath.reset();
329 | int parentMiddleX = mParentView.getLeft() + mParentView.getMeasuredWidth() / 2;
330 | mPath.moveTo(parentMiddleX, mItemTop);
331 | mPath.lineTo(parentMiddleX - mTriangleHeight, mFirstItemTop);
332 | mPath.lineTo(parentMiddleX + mTriangleHeight, mFirstItemTop);
333 | canvas.drawPath(mPath, mPaint);
334 | }
335 |
336 | if (i == 0) {
337 | mPath.reset();
338 | mPath.moveTo(mItemLeft, mFirstItemTop + mItemHeight);
339 | mPath.lineTo(mItemLeft + mItemWidth, mFirstItemTop + mItemHeight);
340 | mPath.lineTo(mItemLeft + mItemWidth, mFirstItemTop + mCorner);
341 | mPath.quadTo(mItemLeft + mItemWidth, mFirstItemTop, mItemLeft + mItemWidth - mCorner, mFirstItemTop);
342 | mPath.lineTo(mItemLeft + mCorner, mFirstItemTop);
343 | mPath.quadTo(mItemLeft, mFirstItemTop, mItemLeft, mFirstItemTop + mCorner);
344 | mPath.lineTo(mItemLeft, mFirstItemTop + mItemHeight);
345 | canvas.drawPath(mPath, mPaint);
346 | } else if (i == mItemList.size() - 1) {
347 | mPath.reset();
348 | mPath.moveTo(mItemLeft, mFirstItemTop + i * mItemHeight);
349 | mPath.lineTo(mItemLeft + mItemWidth, mFirstItemTop + i * mItemHeight);
350 | mPath.lineTo(mItemLeft + mItemWidth, mFirstItemTop + (i + 1) * mItemHeight - mCorner);
351 | mPath.quadTo(mItemLeft + mItemWidth, mFirstItemTop + (i + 1) * mItemHeight, mItemLeft + mItemWidth - mCorner, mFirstItemTop + (i + 1) * mItemHeight);
352 | mPath.lineTo(mItemLeft + mCorner, mFirstItemTop + (i + 1) * mItemHeight);
353 | mPath.quadTo(mItemLeft, mFirstItemTop + (i + 1) * mItemHeight, mItemLeft, mFirstItemTop + (i + 1) * mItemHeight - mCorner);
354 | mPath.lineTo(mItemLeft, mFirstItemTop + i * mItemHeight);
355 | canvas.drawPath(mPath, mPaint);
356 | } else {
357 | canvas.drawRect(mItemLeft, mFirstItemTop + i * mItemHeight, mItemLeft + mItemWidth, mFirstItemTop + mItemHeight + i * mItemHeight, mPaint);
358 | }
359 |
360 | mItemRectList.add(new RectF(mItemLeft, mFirstItemTop + i * mItemHeight, mItemLeft + mItemWidth, mFirstItemTop + mItemHeight + i * mItemHeight));
361 |
362 | drawTitle(canvas, i);
363 | drawIcon(canvas, i);
364 |
365 | mCamera.restore();
366 | canvas.restore();
367 | }
368 | }
369 |
370 | private void drawTitle(Canvas canvas, int position) {
371 | ShareItem shareItem = mItemList.get(position);
372 | mPaint.setColor(shareItem.titleColor);
373 | if (mStatus == STATUS_DOWN) {
374 | canvas.drawText(shareItem.title, mItemLeft + dip2px(8)
375 | , mFirstItemTop + getTextHeight(shareItem.title, mPaint) / 2 + mItemHeight / 2 + position * mItemHeight, mPaint);
376 | } else if (mStatus == STATUS_UP) {
377 | canvas.drawText(shareItem.title, mItemLeft + dip2px(8)
378 | , mFirstItemTop + getTextHeight(shareItem.title, mPaint) / 2 - (mItemHeight / 2 + (mItemList.size() - position - 1) * mItemHeight), mPaint);
379 | }
380 | }
381 |
382 | private void drawIcon(Canvas canvas, int position) {
383 | ShareItem shareItem = mItemList.get(position);
384 | if (shareItem.icon != null) {
385 | float left = mItemLeft + mItemWidth - mItemHeight / 2 - dip2px(6);
386 | if (mStatus == STATUS_DOWN) {
387 | float top = mFirstItemTop + mItemHeight / 4 + position * mItemHeight;
388 | canvas.drawBitmap(shareItem.icon, null, new RectF(left, top, left + mItemHeight / 2, top + mItemHeight / 2), mPaint);
389 | } else if (mStatus == STATUS_UP) {
390 | float top = mFirstItemTop - (mItemHeight / 4 + (mItemList.size() - position - 1) * mItemHeight);
391 | canvas.drawBitmap(shareItem.icon, null, new RectF(left - mItemHeight / 2, top - mItemHeight / 2, left, top), mPaint);
392 | }
393 |
394 | }
395 | }
396 |
397 | public void startAnim() {
398 |
399 | if (mItemList.size() == 0) {
400 | throw new RuntimeException("At least set one shareItem");
401 | }
402 |
403 | mTotalAnimList.clear();
404 |
405 | for (int i = 0; i < mItemList.size(); i++) {
406 | final Collection animList = new ArrayList<>();
407 |
408 | ValueAnimator itemShakeAnim;
409 | switch (mStatus) {
410 | case STATUS_DOWN:
411 | itemShakeAnim = ValueAnimator.ofFloat(0, 3, 0);
412 | break;
413 | case STATUS_UP:
414 | itemShakeAnim = ValueAnimator.ofFloat(0, -3, 0);
415 | break;
416 | default:
417 | itemShakeAnim = ValueAnimator.ofFloat(0);
418 | break;
419 | }
420 | itemShakeAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
421 | @Override
422 | public void onAnimationUpdate(ValueAnimator animation) {
423 | mItemShakeDegree = (float) animation.getAnimatedValue();
424 | }
425 | });
426 |
427 | ValueAnimator itemFlipAnim = ValueAnimator.ofFloat(-90, 8, 0);
428 | final int index = i;
429 | itemFlipAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
430 | @Override
431 | public void onAnimationUpdate(ValueAnimator animation) {
432 | mDegree = (float) animation.getAnimatedValue();
433 | mCurrentItem = index;
434 | invalidate();
435 | }
436 | });
437 | animList.add(itemFlipAnim);
438 | animList.add(itemShakeAnim);
439 | AnimatorSet set = new AnimatorSet();
440 | set.setDuration(mDuration);
441 | set.setInterpolator(new LinearInterpolator());
442 | set.playTogether(animList);
443 | mTotalAnimList.add(set);
444 | set.addListener(new MyAnimListener() {
445 | @Override
446 | public void onAnimationEnd(Animator animation) {
447 | if (index + 1 < mItemList.size()) {
448 | mTotalAnimList.get(index + 1).start();
449 | }
450 | }
451 | });
452 |
453 | }
454 |
455 | mTotalAnimList.get(0).start();
456 |
457 | }
458 |
459 | public void setShareItemList(final List list) {
460 | mItemList.clear();
461 | List items = list;
462 | for (ShareItem item : items) {
463 | if (!TextUtils.isEmpty(item.title)) {
464 | item.title = updateTitle(item.title, item.icon != null);
465 | } else {
466 | item.title = "";
467 | }
468 |
469 | mItemList.add(item);
470 | }
471 | }
472 |
473 | private String updateTitle(String title, boolean hasIcon) {
474 | int textLength = title.length();
475 | String suffix = "";
476 | while (getTextWidth(title.substring(0, textLength) + "...", mPaint) > mItemWidth - dip2px(10) - (hasIcon ? (dip2px(6) + mItemHeight / 2) : 0)) {
477 | textLength--;
478 | suffix = "...";
479 | }
480 | return title.substring(0, textLength) + suffix;
481 | }
482 |
483 | public void setItemDuration(int mils) {
484 | mDuration = mils;
485 | }
486 |
487 | public void setBackgroundColor(int color) {
488 | mBackgroundColor = color;
489 | }
490 |
491 | public void setSeparateLineColor(int separateLineColor) {
492 | mSeparateLineColor = separateLineColor;
493 | }
494 |
495 | private void dismiss() {
496 | for (Animator animator : mTotalAnimList) {
497 | animator.cancel();
498 | }
499 |
500 | if (!mAlphaAnim.isRunning()) {
501 | mAlphaAnim.start();
502 | }
503 | }
504 |
505 | private void removeView() {
506 | ViewGroup vg = (ViewGroup) this.getParent();
507 | if (vg != null) {
508 | vg.removeView(this);
509 | }
510 | }
511 |
512 | @Override
513 | public boolean onTouchEvent(MotionEvent event) {
514 | switch (event.getAction()) {
515 | case MotionEvent.ACTION_DOWN:
516 |
517 | return true;
518 | case MotionEvent.ACTION_UP:
519 | for (int i = 0; i < mItemRectList.size(); i++) {
520 | if (onFlipClickListener != null && isPointInRect(new PointF(event.getX(), event.getY()), mItemRectList.get(i))) {
521 | onFlipClickListener.onItemClick(i);
522 | }
523 | }
524 | dismiss();
525 | return true;
526 | }
527 | return true;
528 | }
529 |
530 | private boolean isPointInRect(PointF pointF, RectF targetRect) {
531 | if (pointF.x < targetRect.left) {
532 | return false;
533 | }
534 | if (pointF.x > targetRect.right) {
535 | return false;
536 | }
537 | if (pointF.y < targetRect.top) {
538 | return false;
539 | }
540 | if (pointF.y > targetRect.bottom) {
541 | return false;
542 | }
543 | return true;
544 | }
545 |
546 | private int dip2px(float dipValue) {
547 | final float scale = getContext().getResources().getDisplayMetrics().density;
548 | return (int) (dipValue * scale + 0.5f);
549 | }
550 |
551 | private int sp2px(float spValue) {
552 | final float fontScale = getContext().getResources().getDisplayMetrics().scaledDensity;
553 | return (int) (spValue * fontScale + 0.5f);
554 | }
555 |
556 | private float getTextHeight(String text, Paint paint) {
557 | Rect rect = new Rect();
558 | paint.getTextBounds(text, 0, text.length(), rect);
559 | return rect.height() / 1.1f;
560 | }
561 |
562 | private float getTextWidth(String text, Paint paint) {
563 | return paint.measureText(text);
564 | }
565 |
566 | @IntDef(flag = true, value = {TYPE_VERTICLE, TYPE_HORIZONTAL, TYPE_SLIDE})
567 | public @interface AnimType {
568 | }
569 |
570 | @AnimType
571 | public void setAnimType(@AnimType int animType) {
572 | mAnimType = animType;
573 | }
574 |
575 | public void setOnFlipClickListener(OnFlipClickListener onFlipClickListener) {
576 | this.onFlipClickListener = onFlipClickListener;
577 | }
578 |
579 | public interface OnFlipClickListener {
580 | void onItemClick(int position);
581 |
582 | void dismiss();
583 | }
584 |
585 | private abstract class MyAnimListener implements Animator.AnimatorListener {
586 | @Override
587 | public void onAnimationStart(Animator animation) {
588 |
589 | }
590 |
591 | @Override
592 | public void onAnimationCancel(Animator animation) {
593 |
594 | }
595 |
596 | @Override
597 | public void onAnimationRepeat(Animator animation) {
598 |
599 | }
600 | }
601 |
602 | public static class Builder {
603 |
604 | private Activity mActivity;
605 | private View mParentView;
606 | private List mShareItemList = new ArrayList<>();
607 | private int mMilliSecond = 300;
608 | private int mBgColor = 0x00FFFFFF;
609 | private int mAnimType = FlipShareView.TYPE_VERTICLE;
610 | private int mSeparateLineColor = Color.TRANSPARENT;
611 |
612 | public Builder(Activity activity, View parentView) {
613 | mActivity = activity;
614 | mParentView = parentView;
615 | }
616 |
617 | public Builder addItem(ShareItem shareItem) {
618 | mShareItemList.add(shareItem);
619 | return this;
620 | }
621 |
622 | public Builder addItems(List list) {
623 | mShareItemList.addAll(list);
624 | return this;
625 | }
626 |
627 | public Builder setItemDuration(int mils) {
628 | mMilliSecond = mils;
629 | return this;
630 | }
631 |
632 | public Builder setAnimType(@AnimType int animType) {
633 | mAnimType = animType;
634 | return this;
635 | }
636 |
637 | public Builder setBackgroundColor(int color) {
638 | mBgColor = color;
639 | return this;
640 | }
641 |
642 | public Builder setSeparateLineColor(int color) {
643 | mSeparateLineColor = color;
644 | return this;
645 | }
646 |
647 | public FlipShareView create() {
648 | FlipShareView flipShare = new FlipShareView(mActivity.getBaseContext(), mActivity.getWindow(), mParentView);
649 | flipShare.setShareItemList(mShareItemList);
650 | flipShare.setItemDuration(mMilliSecond);
651 | flipShare.setBackgroundColor(mBgColor);
652 | flipShare.setAnimType(mAnimType);
653 | flipShare.setSeparateLineColor(mSeparateLineColor);
654 | flipShare.startAnim();
655 | return flipShare;
656 | }
657 |
658 | }
659 |
660 | }
661 |
--------------------------------------------------------------------------------
/FlipShare/src/main/java/me/wangyuwei/flipshare/ShareItem.java:
--------------------------------------------------------------------------------
1 | package me.wangyuwei.flipshare;
2 |
3 | import android.graphics.Bitmap;
4 | import android.graphics.Color;
5 |
6 | /**
7 | * 作者: 巴掌 on 16/9/3 14:05
8 | * Github: https://github.com/JeasonWong
9 | */
10 | public class ShareItem {
11 |
12 | public String title;
13 | public int titleColor = Color.BLACK;
14 | public int bgColor = Color.WHITE;
15 | public Bitmap icon;
16 |
17 | public ShareItem(String title) {
18 | this.title = title;
19 | }
20 |
21 | public ShareItem(String title, Bitmap icon) {
22 | this.title = title;
23 | this.icon = icon;
24 | }
25 |
26 | public ShareItem(String title, int bgColor) {
27 | this.title = title;
28 | this.bgColor = bgColor;
29 | }
30 |
31 | public ShareItem(String title, int titleColor, int bgColor) {
32 | this.title = title;
33 | this.titleColor = titleColor;
34 | this.bgColor = bgColor;
35 | }
36 |
37 | public ShareItem(String title, int bgColor, Bitmap icon) {
38 | this.title = title;
39 | this.bgColor = bgColor;
40 | this.icon = icon;
41 | }
42 |
43 | public ShareItem(String title, int titleColor, int bgColor, Bitmap icon) {
44 | this.title = title;
45 | this.titleColor = titleColor;
46 | this.bgColor = bgColor;
47 | this.icon = icon;
48 | }
49 |
50 | @Override
51 | public String toString() {
52 | return "ShareItem{"
53 | + "title='" + title + '\''
54 | + ", titleColor=" + titleColor
55 | + ", bgColor=" + bgColor
56 | + ", icon=" + icon
57 | + '}';
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/FlipShare/src/test/java/me/wangyuwei/flipshare/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package me.wangyuwei.flipshare;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * To work on unit tests, switch the Test Artifact in the Build Variants view.
9 | */
10 | public class ExampleUnitTest {
11 | @Test
12 | public void addition_isCorrect() throws Exception {
13 | assertEquals(4, 2 + 2);
14 | }
15 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## What's FlipShare ?
2 | It's a cool way to show share widget.
3 |
4 | ## Demo
5 |
6 | 
7 |
8 | ## Usage
9 |
10 | step 1. Confirm your parentView to locate the share widget, and then you can custom by yourself.
11 |
12 | ```java
13 | FlipShareView share = new FlipShareView.Builder(this, mBtnLeftTop)
14 | .addItem(new ShareItem("Facebook", Color.WHITE, 0xff43549C, BitmapFactory.decodeResource(getResources(), R.mipmap.ic_facebook)))
15 | .addItem(new ShareItem("Twitter", Color.WHITE, 0xff4999F0, BitmapFactory.decodeResource(getResources(), R.mipmap.ic_twitter)))
16 | .addItem(new ShareItem("Google+", Color.WHITE, 0xffD9392D, BitmapFactory.decodeResource(getResources(), R.mipmap.ic_google)))
17 | .addItem(new ShareItem("http://www.wangyuwei.me", Color.WHITE, 0xff57708A))
18 | .setBackgroundColor(0x60000000)
19 | .setItemDuration(500)
20 | .setSeparateLineColor(0x30000000)
21 | .setAnimType(FlipShareView.TYPE_SLIDE)
22 | .create();
23 | ```
24 | step 2. Recognize some custom Attributes.
25 |
26 | **Animation type**
27 |
28 | ```java
29 | @IntDef(flag = true, value = {TYPE_VERTICLE, TYPE_HORIZONTAL, TYPE_SLIDE})
30 | public @interface AnimType {
31 | }
32 |
33 | ```
34 |
35 | **Builder**
36 |
37 | ```java
38 | public Builder addItem(ShareItem shareItem) {
39 | mShareItemList.add(shareItem);
40 | return this;
41 | }
42 |
43 | public Builder addItems(List list) {
44 | mShareItemList.addAll(list);
45 | return this;
46 | }
47 |
48 | public Builder setItemDuration(int mils) {
49 | mMilliSecond = mils;
50 | return this;
51 | }
52 |
53 | public Builder setAnimType(@AnimType int animType) {
54 | mAnimType = animType;
55 | return this;
56 | }
57 |
58 | public Builder setBackgroundColor(int color) {
59 | mBgColor = color;
60 | return this;
61 | }
62 |
63 | public Builder setSeparateLineColor(int color) {
64 | mSeparateLineColor = color;
65 | return this;
66 | }
67 | ```
68 |
69 | step 3. Add OnFlipClickListener to get some callback.
70 |
71 | ```java
72 | share.setOnFlipClickListener(new FlipShareView.OnFlipClickListener() {
73 | @Override
74 | public void onItemClick(int position) {
75 | Toast.makeText(MainActivity.this, "position " + position + " is clicked.", Toast.LENGTH_SHORT).show();
76 | }
77 |
78 | @Override
79 | public void dismiss() {
80 | }
81 | });
82 | ```
83 |
84 | ## Import
85 |
86 | Step 1. Add it in your project's build.gradle at the end of repositories:
87 |
88 | ```gradle
89 | repositories {
90 | maven {
91 | url 'https://dl.bintray.com/wangyuwei/maven'
92 | }
93 | }
94 | ```
95 |
96 | Step 2. Add the dependency:
97 |
98 | ```gradle
99 | dependencies {
100 | compile 'me.wangyuwei:FlipShare:1.0.2'
101 | }
102 | ```
103 |
104 | ### About Me
105 |
106 | [Weibo](http://weibo.com/WongYuwei)
107 |
108 | [Blog](http://www.wangyuwei.me)
109 |
110 | ### QQ Group 欢迎讨论
111 |
112 | **479729938**
113 |
114 | ##**License**
115 |
116 | ```license
117 | Copyright [2016] [JeasonWong of copyright owner]
118 |
119 | Licensed under the Apache License, Version 2.0 (the "License");
120 | you may not use this file except in compliance with the License.
121 | You may obtain a copy of the License at
122 |
123 | http://www.apache.org/licenses/LICENSE-2.0
124 |
125 | Unless required by applicable law or agreed to in writing, software
126 | distributed under the License is distributed on an "AS IS" BASIS,
127 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
128 | See the License for the specific language governing permissions and
129 | limitations under the License.
130 | ```
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 23
5 | buildToolsVersion "23.0.1"
6 |
7 | defaultConfig {
8 | applicationId "me.wangyuwei.coolshare"
9 | minSdkVersion 15
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(dir: 'libs', include: ['*.jar'])
24 | testCompile 'junit:junit:4.12'
25 | compile 'com.android.support:appcompat-v7:23.1.1'
26 | compile project(':FlipShare')
27 | }
28 |
--------------------------------------------------------------------------------
/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 /Users/wscn/Documents/android-sdk-macosx/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/androidTest/java/me/wangyuwei/flipshare/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package me.wangyuwei.flipshare;
2 |
3 | import android.app.Application;
4 | import android.test.ApplicationTestCase;
5 |
6 | /**
7 | * Testing Fundamentals
8 | */
9 | public class ApplicationTest extends ApplicationTestCase {
10 | public ApplicationTest() {
11 | super(Application.class);
12 | }
13 | }
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/app/src/main/java/me/wangyuwei/flipshare/MainActivity.java:
--------------------------------------------------------------------------------
1 | package me.wangyuwei.flipshare;
2 |
3 | import android.graphics.BitmapFactory;
4 | import android.graphics.Color;
5 | import android.os.Bundle;
6 | import android.support.v7.app.AppCompatActivity;
7 | import android.view.View;
8 | import android.widget.Button;
9 | import android.widget.Toast;
10 |
11 | public class MainActivity extends AppCompatActivity implements View.OnClickListener {
12 |
13 | private Button mBtnLeftTop;
14 | private Button mBtnMiddleTop;
15 | private Button mBtnRightTop;
16 | private Button mBtnLeftBottom;
17 | private Button mBtnMiddleBottom;
18 | private Button mBtnRightBottom;
19 |
20 | @Override
21 | protected void onCreate(Bundle savedInstanceState) {
22 | super.onCreate(savedInstanceState);
23 | setContentView(R.layout.activity_main);
24 |
25 | mBtnLeftTop = (Button) findViewById(R.id.btn_left_top);
26 | mBtnMiddleTop = (Button) findViewById(R.id.btn_middle_top);
27 | mBtnRightTop = (Button) findViewById(R.id.btn_right_top);
28 | mBtnLeftBottom = (Button) findViewById(R.id.btn_left_bottom);
29 | mBtnMiddleBottom = (Button) findViewById(R.id.btn_middle_bottom);
30 | mBtnRightBottom = (Button) findViewById(R.id.btn_right_bottom);
31 | mBtnLeftTop.setOnClickListener(this);
32 | mBtnMiddleTop.setOnClickListener(this);
33 | mBtnRightTop.setOnClickListener(this);
34 | mBtnLeftBottom.setOnClickListener(this);
35 | mBtnMiddleBottom.setOnClickListener(this);
36 | mBtnRightBottom.setOnClickListener(this);
37 |
38 | }
39 |
40 | @Override
41 | public void onClick(View v) {
42 | switch (v.getId()) {
43 | case R.id.btn_left_top:
44 | FlipShareView share = new FlipShareView.Builder(this, mBtnLeftTop)
45 | .addItem(new ShareItem("Facebook", Color.WHITE, 0xff43549C, BitmapFactory.decodeResource(getResources(), R.mipmap.ic_facebook)))
46 | .addItem(new ShareItem("Twitter", Color.WHITE, 0xff4999F0, BitmapFactory.decodeResource(getResources(), R.mipmap.ic_twitter)))
47 | .addItem(new ShareItem("Google+", Color.WHITE, 0xffD9392D, BitmapFactory.decodeResource(getResources(), R.mipmap.ic_google)))
48 | .addItem(new ShareItem("http://www.wangyuwei.me", Color.WHITE, 0xff57708A))
49 | .setBackgroundColor(0x60000000)
50 | .create();
51 |
52 | share.setOnFlipClickListener(new FlipShareView.OnFlipClickListener() {
53 | @Override
54 | public void onItemClick(int position) {
55 | Toast.makeText(MainActivity.this, "position " + position + " is clicked.", Toast.LENGTH_SHORT).show();
56 | }
57 |
58 | @Override
59 | public void dismiss() {
60 |
61 | }
62 | });
63 |
64 | break;
65 | case R.id.btn_middle_top:
66 |
67 | new FlipShareView.Builder(this, mBtnMiddleTop)
68 | .addItem(new ShareItem("Facebook", Color.WHITE, 0xff43549C, BitmapFactory.decodeResource(getResources(), R.mipmap.ic_facebook)))
69 | .addItem(new ShareItem("Wangyuwei", Color.WHITE, 0xff4999F0))
70 | .addItem(new ShareItem("Wangyuweiwangyuwei", Color.WHITE, 0xffD9392D))
71 | .addItem(new ShareItem("纯文字也可以", Color.WHITE, 0xff57708A))
72 | .setAnimType(FlipShareView.TYPE_HORIZONTAL)
73 | .create();
74 | break;
75 | case R.id.btn_right_top:
76 | new FlipShareView.Builder(this, mBtnRightTop)
77 | .addItem(new ShareItem("Facebook", Color.WHITE, 0xff43549C, BitmapFactory.decodeResource(getResources(), R.mipmap.ic_facebook)))
78 | .addItem(new ShareItem("Twitter", Color.WHITE, 0xff4999F0, BitmapFactory.decodeResource(getResources(), R.mipmap.ic_twitter)))
79 | .addItem(new ShareItem("Google+", Color.WHITE, 0xffD9392D, BitmapFactory.decodeResource(getResources(), R.mipmap.ic_google)))
80 | .addItem(new ShareItem("http://www.wangyuwei.me", Color.WHITE, 0xff57708A))
81 | .setItemDuration(500)
82 | .setBackgroundColor(0x60000000)
83 | .setAnimType(FlipShareView.TYPE_SLIDE)
84 | .create();
85 | break;
86 | case R.id.btn_left_bottom:
87 | new FlipShareView.Builder(this, mBtnLeftBottom)
88 | .addItem(new ShareItem("Facebook"))
89 | .addItem(new ShareItem("Twitter"))
90 | .addItem(new ShareItem("Google+"))
91 | .addItem(new ShareItem("http://www.wangyuwei.me", Color.WHITE, 0xff57708A))
92 | .addItem(new ShareItem("http://www.wangyuwei.me", Color.WHITE, 0xff57708A))
93 | .setSeparateLineColor(0x30000000)
94 | .setAnimType(FlipShareView.TYPE_HORIZONTAL)
95 | .create();
96 | break;
97 | case R.id.btn_middle_bottom:
98 | FlipShareView shareBottom = new FlipShareView.Builder(this, mBtnMiddleBottom)
99 | .addItem(new ShareItem("Facebook"))
100 | .addItem(new ShareItem("Twitter"))
101 | .addItem(new ShareItem("Google+"))
102 | .addItem(new ShareItem("http://www.wangyuwei.me", Color.WHITE, 0xff57708A))
103 | .setSeparateLineColor(0x30000000)
104 | .setBackgroundColor(0x60000000)
105 | .setAnimType(FlipShareView.TYPE_SLIDE)
106 | .create();
107 | shareBottom.setOnFlipClickListener(new FlipShareView.OnFlipClickListener() {
108 | @Override
109 | public void onItemClick(int position) {
110 | Toast.makeText(MainActivity.this, "position " + position + " is clicked.", Toast.LENGTH_SHORT).show();
111 | }
112 |
113 | @Override
114 | public void dismiss() {
115 |
116 | }
117 | });
118 | break;
119 | case R.id.btn_right_bottom:
120 | new FlipShareView.Builder(this, mBtnRightBottom)
121 | .addItem(new ShareItem("Facebook", Color.WHITE, 0xff43549C, BitmapFactory.decodeResource(getResources(), R.mipmap.ic_facebook)))
122 | .addItem(new ShareItem("Twitter", Color.WHITE, 0xff4999F0, BitmapFactory.decodeResource(getResources(), R.mipmap.ic_twitter)))
123 | .addItem(new ShareItem("Google+", Color.WHITE, 0xffD9392D, BitmapFactory.decodeResource(getResources(), R.mipmap.ic_google)))
124 | .addItem(new ShareItem("http://www.wangyuwei.me", Color.WHITE, 0xff57708A))
125 | .create();
126 | break;
127 | }
128 | }
129 | }
130 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
11 |
12 |
18 |
19 |
25 |
26 |
32 |
33 |
40 |
41 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JeasonWong/FlipShare/efe83cf892e02a4fba33228a761c18bb97ad8177/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JeasonWong/FlipShare/efe83cf892e02a4fba33228a761c18bb97ad8177/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_facebook.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JeasonWong/FlipShare/efe83cf892e02a4fba33228a761c18bb97ad8177/app/src/main/res/mipmap-xhdpi/ic_facebook.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_google.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JeasonWong/FlipShare/efe83cf892e02a4fba33228a761c18bb97ad8177/app/src/main/res/mipmap-xhdpi/ic_google.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JeasonWong/FlipShare/efe83cf892e02a4fba33228a761c18bb97ad8177/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_twitter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JeasonWong/FlipShare/efe83cf892e02a4fba33228a761c18bb97ad8177/app/src/main/res/mipmap-xhdpi/ic_twitter.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JeasonWong/FlipShare/efe83cf892e02a4fba33228a761c18bb97ad8177/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JeasonWong/FlipShare/efe83cf892e02a4fba33228a761c18bb97ad8177/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 | FlipShare
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/test/java/me/wangyuwei/flipshare/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package me.wangyuwei.flipshare;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * To work on unit tests, switch the Test Artifact in the Build Variants view.
9 | */
10 | public class ExampleUnitTest {
11 | @Test
12 | public void addition_isCorrect() throws Exception {
13 | assertEquals(4, 2 + 2);
14 | }
15 | }
--------------------------------------------------------------------------------
/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.1.0'
9 | classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.2'
10 | classpath 'com.github.dcendents:android-maven-gradle-plugin:1.3'
11 | // NOTE: Do not place your application dependencies here; they belong
12 | // in the individual module build.gradle files
13 | }
14 | }
15 |
16 | allprojects {
17 | repositories {
18 | jcenter()
19 | }
20 |
21 | apply plugin: 'checkstyle'
22 |
23 | checkstyle {
24 | toolVersion '6.1.1'
25 | showViolations true
26 | }
27 |
28 | task checkstyle(type: Checkstyle) {
29 | source 'src'
30 | include '**/*.java'
31 | exclude '**/gen/**'
32 | ignoreFailures false
33 | configFile new File(rootDir, "checkstyle.xml")
34 | // empty classpath
35 | classpath = files()
36 | }
37 |
38 | }
39 |
40 | task clean(type: Delete) {
41 | delete rootProject.buildDir
42 | }
43 |
44 |
--------------------------------------------------------------------------------
/checkstyle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
--------------------------------------------------------------------------------
/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/JeasonWong/FlipShare/efe83cf892e02a4fba33228a761c18bb97ad8177/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-2.10-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 |
--------------------------------------------------------------------------------
/screenshots/flipshare.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JeasonWong/FlipShare/efe83cf892e02a4fba33228a761c18bb97ad8177/screenshots/flipshare.gif
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':FlipShare'
2 |
--------------------------------------------------------------------------------