diff --git a/README.md b/README.md index fc2b0bf..46f291b 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Button which is visible while user holds it. Main use case is controlling audio Add library as dependency to your `build.gradle`. ``` -compile 'com.dewarder:holdingbutton:0.0.9' +compile 'com.dewarder:holdingbutton:0.1.0' ``` ## How to use diff --git a/build.gradle b/build.gradle index 1e7c0f4..ae26e3e 100644 --- a/build.gradle +++ b/build.gradle @@ -9,6 +9,11 @@ buildscript { } } -repositories { - mavenCentral() +allprojects { + repositories { + mavenCentral() + maven { + url 'https://maven.google.com' + } + } } \ No newline at end of file diff --git a/holdingbutton/build.gradle b/holdingbutton/build.gradle index 9305508..5442e2a 100644 --- a/holdingbutton/build.gradle +++ b/holdingbutton/build.gradle @@ -3,7 +3,7 @@ apply plugin: 'com.github.dcendents.android-maven' apply plugin: 'com.jfrog.bintray' ext { - artifactVersion = '0.0.9' + artifactVersion = '0.1.0' artifactName = 'holdingbutton' siteUrl = 'https://github.com/dewarder/HoldingButton' gitUrl = 'https://github.com/dewarder/HoldingButton.git' @@ -13,18 +13,16 @@ version = artifactVersion group = 'com.dewarder' android { - compileSdkVersion 25 - buildToolsVersion "25.0.2" + compileSdkVersion 26 + buildToolsVersion "25.0.3" defaultConfig { minSdkVersion 15 - targetSdkVersion 25 + targetSdkVersion 26 versionCode 1 versionName artifactVersion - - testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" - } + buildTypes { release { minifyEnabled false @@ -35,10 +33,9 @@ android { dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) - compile 'com.android.support:support-annotations:25.2.0' + compile 'com.android.support:support-annotations:25.3.1' } - install { repositories.mavenInstaller { pom { @@ -110,7 +107,7 @@ bintray { vcsUrl = gitUrl version { name = artifactVersion - desc = 'Fixed touch listener area' + desc = 'Add RTL support. Upgrade dependencies versions.' released = new Date() vcsTag = "$artifactVersion" } diff --git a/holdingbutton/src/main/java/com/dewarder/holdinglibrary/ColorUtils.java b/holdingbutton/src/main/java/com/dewarder/holdinglibrary/ColorHelper.java similarity index 92% rename from holdingbutton/src/main/java/com/dewarder/holdinglibrary/ColorUtils.java rename to holdingbutton/src/main/java/com/dewarder/holdinglibrary/ColorHelper.java index afe9625..b5c7fe2 100644 --- a/holdingbutton/src/main/java/com/dewarder/holdinglibrary/ColorUtils.java +++ b/holdingbutton/src/main/java/com/dewarder/holdinglibrary/ColorHelper.java @@ -18,9 +18,9 @@ import android.graphics.Color; -public final class ColorUtils { +final class ColorHelper { - public static int blend(int from, int to, float ratio) { + static int blend(int from, int to, float ratio) { float inverseRatio = 1f - ratio; float a = Color.alpha(to) * ratio + Color.alpha(from) * inverseRatio; diff --git a/holdingbutton/src/main/java/com/dewarder/holdinglibrary/DirectionHelper.java b/holdingbutton/src/main/java/com/dewarder/holdinglibrary/DirectionHelper.java new file mode 100644 index 0000000..7afff29 --- /dev/null +++ b/holdingbutton/src/main/java/com/dewarder/holdinglibrary/DirectionHelper.java @@ -0,0 +1,39 @@ +package com.dewarder.holdinglibrary; + +import android.os.Build; +import android.view.View; + +import com.dewarder.holdinglibrary.HoldingButtonLayout.Direction; +import com.dewarder.holdinglibrary.HoldingButtonLayout.LayoutDirection; + +final class DirectionHelper { + + static LayoutDirection resolveLayoutDirection(HoldingButtonLayout view) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) { + return LayoutDirection.LTR; + } + + int rawDirection = view.getResources().getConfiguration().getLayoutDirection(); + if (rawDirection == View.LAYOUT_DIRECTION_LTR) { + return LayoutDirection.LTR; + } else { + return LayoutDirection.RTL; + } + } + + static Direction resolveDefaultSlidingDirection(HoldingButtonLayout view) { + if (resolveLayoutDirection(view) == LayoutDirection.LTR) { + return Direction.START; + } else { + return Direction.END; + } + } + + static Direction adaptSlidingDirection(HoldingButtonLayout view, Direction direction) { + if (resolveLayoutDirection(view) == LayoutDirection.LTR) { + return direction; + } else { + return direction.toRtl(); + } + } +} diff --git a/holdingbutton/src/main/java/com/dewarder/holdinglibrary/HoldingButtonLayout.java b/holdingbutton/src/main/java/com/dewarder/holdinglibrary/HoldingButtonLayout.java index cd1dbc0..35485cf 100644 --- a/holdingbutton/src/main/java/com/dewarder/holdinglibrary/HoldingButtonLayout.java +++ b/holdingbutton/src/main/java/com/dewarder/holdinglibrary/HoldingButtonLayout.java @@ -42,10 +42,16 @@ public class HoldingButtonLayout extends FrameLayout { - private int mHoldingViewId = -1; + private static final float DEFAULT_CANCEL_OFFSET = 0.3f; + private static final float COLLAPSING_SCALE_Y_VALUE_START = 0.8f; + private static final float COLLAPSING_SCALE_Y_VALUE_END = 1f; + private static final float COLLAPSING_ALPHA_VALUE_START = 0f; + private static final float COLLAPSING_ALPHA_VALUE_END = 1f; + + private int mHoldingViewId = NO_ID; private View mHoldingView; private Rect mHoldingViewRect = new Rect(); - private float mCancelOffset = 0.3f; + private float mCancelOffset = DEFAULT_CANCEL_OFFSET; private float mDeltaX; private View mHoldingCircle; @@ -54,12 +60,15 @@ public class HoldingButtonLayout extends FrameLayout { private int[] mViewLocation = new int[2]; private int[] mHoldingViewLocation = new int[2]; - private Direction mDirection = Direction.START; + private LayoutDirection mLayoutDirection = LayoutDirection.LTR; + private Direction mDirection; private boolean mAnimateHoldingView = true; private boolean mButtonEnabled = true; private boolean mIsCancel = false; private boolean mIsExpanded = false; + private int mCollapsingAnimationDuration; + private HoldingButtonTouchListener mTouchListener = new SimpleHoldingButtonTouchListener(); private final DrawableListener mDrawableListener = new DrawableListener(); private final List mListeners = new ArrayList<>(); @@ -95,8 +104,11 @@ public HoldingButtonLayout(@NonNull Context context, } private void init(Context context, AttributeSet attrs, @AttrRes int defStyleAttr, @StyleRes int defStyleRes) { + mCollapsingAnimationDuration = getResources().getInteger(android.R.integer.config_shortAnimTime); + mHoldingDrawable = new HoldingDrawable(); mHoldingDrawable.setListener(mDrawableListener); + mLayoutDirection = DirectionHelper.resolveLayoutDirection(this); if (attrs != null) { TypedArray array = context.getTheme().obtainStyledAttributes(attrs, @@ -130,7 +142,7 @@ private void init(Context context, AttributeSet attrs, @AttrRes int defStyleAttr } if (array.hasValue(R.styleable.HoldingButtonLayout_hbl_holding_view)) { - mHoldingViewId = array.getResourceId(R.styleable.HoldingButtonLayout_hbl_holding_view, -1); + mHoldingViewId = array.getResourceId(R.styleable.HoldingButtonLayout_hbl_holding_view, NO_ID); } if (array.hasValue(R.styleable.HoldingButtonLayout_hbl_animate_holding_view)) { @@ -166,12 +178,18 @@ private void init(Context context, AttributeSet attrs, @AttrRes int defStyleAttr } if (array.hasValue(R.styleable.HoldingButtonLayout_hbl_direction)) { - int flag = array.getInt(R.styleable.HoldingButtonLayout_hbl_direction, 0); - mDirection = Direction.fromFlag(flag); + int directionFlag = array.getInt(R.styleable.HoldingButtonLayout_hbl_direction, -1); + if (directionFlag != -1) { + mDirection = DirectionHelper.adaptSlidingDirection(this, Direction.fromFlag(directionFlag)); + } } array.recycle(); } + + if (mDirection == null) { + mDirection = DirectionHelper.resolveDefaultSlidingDirection(this); + } } @Override @@ -196,16 +214,20 @@ public boolean onTouchEvent(MotionEvent event) { mHoldingView.getLocationInWindow(mHoldingViewLocation); getLocationInWindow(mViewLocation); - int centerX = mHoldingViewLocation[0] + mHoldingView.getWidth() / 2; - int centerY = mHoldingViewLocation[1] + mHoldingView.getHeight() / 2; + int layoutWidth = getWidth(); + int viewCenterX = mHoldingViewLocation[0] + mHoldingView.getWidth() / 2; + int circleCenterX = mHoldingCircle.getWidth() / 2; + int offsetX = mDirection.getOffsetX(mOffset[0]); + float translationX = mLayoutDirection.calculateTranslationX( + layoutWidth, viewCenterX, circleCenterX, offsetX); - float translationX = centerX - mHoldingCircle.getWidth() / 2f + mDirection.getOffsetX(mOffset[0]); + int centerY = mHoldingViewLocation[1] + mHoldingView.getHeight() / 2; float translationY = centerY - mHoldingCircle.getHeight() / 2f + mOffset[1]; mHoldingCircle.setTranslationX(translationX); mHoldingCircle.setTranslationY(translationY); - mDeltaX = event.getRawX() - centerX - mDirection.getOffsetX(mOffset[0]); + mDeltaX = event.getRawX() - viewCenterX - offsetX; mHoldingDrawable.expand(); mIsCancel = false; @@ -250,7 +272,7 @@ protected void onAttachedToWindow() { @Override protected void onFinishInflate() { super.onFinishInflate(); - if (mHoldingView == null && mHoldingViewId != -1) { + if (mHoldingView == null && mHoldingViewId != NO_ID) { mHoldingView = findViewById(mHoldingViewId); } @@ -394,7 +416,7 @@ public Direction getDirection() { } public void setDirection(Direction direction) { - mDirection = direction; + mDirection = DirectionHelper.adaptSlidingDirection(this, direction); } public void setAnimateHoldingView(boolean animate) { @@ -488,21 +510,72 @@ public void onCollapse() { mHoldingCircle.setVisibility(GONE); if (mAnimateHoldingView) { - mHoldingView.setAlpha(0f); - mHoldingView.setScaleY(0.8f); + mHoldingView.setAlpha(COLLAPSING_ALPHA_VALUE_START); + mHoldingView.setScaleY(COLLAPSING_SCALE_Y_VALUE_START); mHoldingView.setVisibility(VISIBLE); mHoldingView.animate() - .alpha(1f) - .scaleY(1f) - .setDuration(getResources().getInteger(android.R.integer.config_shortAnimTime)) + .alpha(COLLAPSING_ALPHA_VALUE_END) + .scaleY(COLLAPSING_SCALE_Y_VALUE_END) + .setDuration(mCollapsingAnimationDuration) .start(); } } } - public enum Direction { + enum LayoutDirection { + LTR { + @Override + public float calculateTranslationX(int layoutWidth, int viewCenterX, int circleCenterX, int offsetX) { + return viewCenterX - circleCenterX + offsetX; + } + }, + RTL { + @Override + public float calculateTranslationX(int layoutWidth, int viewCenterX, int circleCenterX, int offsetX) { + return -layoutWidth + viewCenterX + circleCenterX + offsetX; + } + }; + + public abstract float calculateTranslationX( + int layoutWidth, int viewCenterX, int circleCenterX, int offsetX); + } + public enum Direction { START(0) { + @Override + int getOffsetX(int offsetX) { + return LEFT.getOffsetX(offsetX); + } + + @Override + float getSlideOffset(float x, float circleCenterX, int[] viewLocation, int viewWidth, int[] holdingViewLocation, int holdingViewWidth, int[] offset) { + return LEFT.getSlideOffset(x, circleCenterX, viewLocation, viewWidth, holdingViewLocation, holdingViewWidth, offset); + } + + @Override + Direction toRtl() { + return END; + } + }, + + END(1) { + @Override + int getOffsetX(int offsetX) { + return RIGHT.getOffsetX(offsetX); + } + + @Override + float getSlideOffset(float x, float circleCenterX, int[] viewLocation, int viewWidth, int[] holdingViewLocation, int holdingViewWidth, int[] offset) { + return RIGHT.getSlideOffset(x, circleCenterX, viewLocation, viewWidth, holdingViewLocation, holdingViewWidth, offset); + } + + @Override + Direction toRtl() { + return START; + } + }, + + LEFT(2) { @Override int getOffsetX(int offsetX) { return offsetX; @@ -514,9 +587,14 @@ float getSlideOffset(float x, float circleCenterX, int[] viewLocation, int viewW float minX = viewLocation[0] + circleCenterX; return (x + circleCenterX - holdingViewCenterX - offset[0]) / (minX - holdingViewCenterX); } + + @Override + Direction toRtl() { + return LEFT; + } }, - END(1) { + RIGHT(3) { @Override int getOffsetX(int offsetX) { return -offsetX; @@ -528,6 +606,11 @@ float getSlideOffset(float x, float circleCenterX, int[] viewLocation, int viewW float maxX = viewLocation[0] + viewWidth - circleCenterX; return (x + circleCenterX - holdingViewCenterX + offset[0]) / (maxX - holdingViewCenterX); } + + @Override + Direction toRtl() { + return RIGHT; + } }; private final int mFlag; @@ -540,7 +623,9 @@ float getSlideOffset(float x, float circleCenterX, int[] viewLocation, int viewW abstract float getSlideOffset(float x, float circleCenterX, int[] viewLocation, int viewWidth, int[] holdingViewLocation, int holdingViewWidth, int[] offset); - public static Direction fromFlag(int flag) { + abstract Direction toRtl(); + + static Direction fromFlag(int flag) { for (Direction direction : values()) { if (direction.mFlag == flag) { return direction; diff --git a/holdingbutton/src/main/java/com/dewarder/holdinglibrary/HoldingDrawable.java b/holdingbutton/src/main/java/com/dewarder/holdinglibrary/HoldingDrawable.java index 379760e..427c28d 100644 --- a/holdingbutton/src/main/java/com/dewarder/holdinglibrary/HoldingDrawable.java +++ b/holdingbutton/src/main/java/com/dewarder/holdinglibrary/HoldingDrawable.java @@ -347,7 +347,7 @@ private ValueAnimator createCancelValueAnimator() { animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator a) { - int color = ColorUtils.blend(from, to, (float) a.getAnimatedValue()); + int color = ColorHelper.blend(from, to, (float) a.getAnimatedValue()); mPaint.setColor(color); mSecondPaint.setColor(color); mSecondPaint.setAlpha(mSecondAlpha); diff --git a/holdingbutton/src/main/res/values/attr.xml b/holdingbutton/src/main/res/values/attr.xml index 273e7c0..ac88995 100644 --- a/holdingbutton/src/main/res/values/attr.xml +++ b/holdingbutton/src/main/res/values/attr.xml @@ -17,6 +17,8 @@ + + diff --git a/holdingbuttonsample/build.gradle b/holdingbuttonsample/build.gradle index 6e19f68..196a76e 100644 --- a/holdingbuttonsample/build.gradle +++ b/holdingbuttonsample/build.gradle @@ -1,19 +1,17 @@ apply plugin: 'com.android.application' android { - compileSdkVersion 25 - buildToolsVersion "25.0.2" + compileSdkVersion 26 + buildToolsVersion "25.0.3" defaultConfig { applicationId "com.dewarder.holdingbuttonsample" minSdkVersion 15 - targetSdkVersion 25 + targetSdkVersion 26 versionCode 1 versionName "1.0" - - testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" - } + buildTypes { release { minifyEnabled false @@ -25,5 +23,5 @@ android { dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile project(":holdingbutton") - compile 'com.android.support:appcompat-v7:25.2.0' + compile 'com.android.support:appcompat-v7:26.0.2' } diff --git a/holdingbuttonsample/src/main/java/com/dewarder/holdingbuttonsample/MainActivity.java b/holdingbuttonsample/src/main/java/com/dewarder/holdingbuttonsample/MainActivity.java index d11180f..2b3e99d 100644 --- a/holdingbuttonsample/src/main/java/com/dewarder/holdingbuttonsample/MainActivity.java +++ b/holdingbuttonsample/src/main/java/com/dewarder/holdingbuttonsample/MainActivity.java @@ -28,7 +28,6 @@ import com.dewarder.holdinglibrary.HoldingButtonLayout; import com.dewarder.holdinglibrary.HoldingButtonLayoutListener; -import com.dewarder.holdinglibrary.HoldingButtonTouchListener; import java.text.DateFormat; import java.text.SimpleDateFormat;