From dafe1a7338b5042d7df593e448d9971eca37b395 Mon Sep 17 00:00:00 2001 From: Alessandro Crugnola Date: Fri, 25 Jan 2019 17:52:09 -0500 Subject: [PATCH] animation for just for the text view --- app/build.gradle | 19 ++++-- .../library/tooltip_demo/MainActivity.kt | 66 +++++++------------ app/src/main/res/anim/custom_anim_enter.xml | 19 ++++++ app/src/main/res/anim/custom_anim_exit.xml | 19 ++++++ app/src/main/res/layout/content_main.xml | 25 ++++--- app/src/main/res/values/styles.xml | 7 +- build.gradle | 5 +- gradle.properties | 4 +- gradle/wrapper/gradle-wrapper.properties | 4 +- .../android/library/xtooltip/Tooltip.kt | 36 ++++++++-- .../android/library/xtooltip/Utils.kt | 47 +++++++++++-- 11 files changed, 177 insertions(+), 74 deletions(-) create mode 100644 app/src/main/res/anim/custom_anim_enter.xml create mode 100644 app/src/main/res/anim/custom_anim_exit.xml diff --git a/app/build.gradle b/app/build.gradle index 62c20896..7d41308b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -8,7 +8,7 @@ android { compileSdkVersion 28 defaultConfig { applicationId "it.sephiroth.android.library.tooltip_demo" - minSdkVersion 18 + minSdkVersion 21 targetSdkVersion 28 versionCode 1 versionName "1.0" @@ -34,18 +34,23 @@ android { dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - implementation 'androidx.appcompat:appcompat:1.0.1' - implementation 'androidx.constraintlayout:constraintlayout:2.0.0-alpha2' - implementation 'com.google.android.material:material:1.1.0-alpha01' + implementation 'androidx.appcompat:appcompat:1.0.2' + implementation 'androidx.constraintlayout:constraintlayout:2.0.0-alpha3' + implementation 'com.google.android.material:material:1.1.0-alpha02' implementation 'com.jakewharton.timber:timber:4.7.1' implementation 'androidx.core:core-ktx:1.0.1' + implementation('com.github.sephiroth74:NumberSlidingPicker:v1.0.0') { + exclude module: 'android-target-tooltip' + } + + implementation project(':xtooltip') testImplementation 'junit:junit:4.12' - androidTestImplementation 'androidx.test:runner:1.1.0' - androidTestImplementation 'androidx.test:rules:1.1.0' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0' + androidTestImplementation 'androidx.test:runner:1.1.1' + androidTestImplementation 'androidx.test:rules:1.1.1' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' androidTestImplementation 'androidx.test.uiautomator:uiautomator:2.2.0' } diff --git a/app/src/main/java/it/sephiroth/android/library/tooltip_demo/MainActivity.kt b/app/src/main/java/it/sephiroth/android/library/tooltip_demo/MainActivity.kt index 0fe2ef8a..f8b1a58e 100644 --- a/app/src/main/java/it/sephiroth/android/library/tooltip_demo/MainActivity.kt +++ b/app/src/main/java/it/sephiroth/android/library/tooltip_demo/MainActivity.kt @@ -1,10 +1,9 @@ package it.sephiroth.android.library.tooltip_demo import android.os.Bundle -import android.widget.SeekBar import androidx.appcompat.app.AppCompatActivity import androidx.core.text.toSpannable -import androidx.core.view.doOnNextLayout +import it.sephiroth.android.library.numberpicker.doOnProgressChanged import it.sephiroth.android.library.xtooltip.ClosePolicy import it.sephiroth.android.library.xtooltip.Tooltip import it.sephiroth.android.library.xtooltip.Typefaces @@ -37,41 +36,28 @@ class MainActivity : AppCompatActivity() { Timber.v("gravity: $gravity") Timber.v("closePolicy: $closePolicy") -// tooltip?.dismiss() - - tooltip?.let { - it.update("123") - - val w = it.contentView!!.measuredWidth - - it.contentView?.doOnNextLayout { - val diff = it.measuredWidth - w - - tooltip?.offsetBy((-diff / 2).toFloat(), 0f) - } - return@setOnClickListener - } + tooltip?.dismiss() tooltip = Tooltip.Builder(this) - .anchor(button, 0, 0, false) - .text(text) - .styleId(style) - .typeface(typeface) - .maxWidth(metrics.widthPixels / 2) - .arrow(arrow) - .floatingAnimation(animation) - .closePolicy(closePolicy) - .showDuration(showDuration) - .overlay(overlay) - .create() + .anchor(button, 0, 0, false) + .text(text) + .styleId(style) + .typeface(typeface) + .maxWidth(metrics.widthPixels / 2) + .arrow(arrow) + .floatingAnimation(animation) + .closePolicy(closePolicy) + .showDuration(showDuration) + .overlay(overlay) + .create() tooltip - ?.doOnHidden { - tooltip = null - } - ?.doOnFailure { } - ?.doOnShown {} - ?.show(button, gravity, true) + ?.doOnHidden { + tooltip = null + } + ?.doOnFailure { } + ?.doOnShown {} + ?.show(button, gravity, true) } button2.setOnClickListener { @@ -79,18 +65,10 @@ class MainActivity : AppCompatActivity() { fragment.showNow(supportFragmentManager, "test_dialog_fragment") } - seekbar_duration.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener { - override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) { - text_duration.text = "Duration:\n${progress}ms" - } - - override fun onStartTrackingTouch(seekBar: SeekBar?) { - } - - override fun onStopTrackingTouch(seekBar: SeekBar?) { - } + seekbar_duration.doOnProgressChanged { numberPicker, progress, formUser -> + text_duration.text = "Duration: ${progress}ms" + } - }) } private fun getClosePolicy(): ClosePolicy { diff --git a/app/src/main/res/anim/custom_anim_enter.xml b/app/src/main/res/anim/custom_anim_enter.xml new file mode 100644 index 00000000..43ae55b7 --- /dev/null +++ b/app/src/main/res/anim/custom_anim_enter.xml @@ -0,0 +1,19 @@ + + + + + + + + diff --git a/app/src/main/res/anim/custom_anim_exit.xml b/app/src/main/res/anim/custom_anim_exit.xml new file mode 100644 index 00000000..aa51fee2 --- /dev/null +++ b/app/src/main/res/anim/custom_anim_exit.xml @@ -0,0 +1,19 @@ + + + + + + + + diff --git a/app/src/main/res/layout/content_main.xml b/app/src/main/res/layout/content_main.xml index ca7bee04..ca2733d8 100644 --- a/app/src/main/res/layout/content_main.xml +++ b/app/src/main/res/layout/content_main.xml @@ -115,19 +115,28 @@ android:orientation="horizontal"> + android:text="Duration: 3000ms" /> - + + + android:progress="3000" + app:picker_max="5000" + app:picker_min="0" + app:picker_orientation="vertical" + app:picker_stepSize="50" + app:picker_tracker="exponential" /> @@ -155,7 +164,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_columnSpan="2" - android:hint="10" + android:hint="Tooltip Text" android:maxLines="2" /> diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index eb72f0c4..4a476c84 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -24,7 +24,7 @@ 6dp 1.2 @style/ToolTipOverlayAltStyle - @android:style/Animation.Dialog + @style/ToolTipAltAnimation + + diff --git a/build.gradle b/build.gradle index f0f0f013..e8855d0d 100644 --- a/build.gradle +++ b/build.gradle @@ -1,13 +1,13 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { - ext.kotlin_version = '1.3.11' + ext.kotlin_version = '1.3.20' repositories { google() jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:3.4.0-beta01' + classpath 'com.android.tools.build:gradle:3.4.0-beta02' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" // NOTE: Do not place your application dependencies here; they belong @@ -19,6 +19,7 @@ allprojects { repositories { google() jcenter() + maven { url 'https://jitpack.io' } } } diff --git a/gradle.properties b/gradle.properties index 05dce52c..0d168987 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ -VERSION_NAME=2.0.3 -VERSION_CODE=104 +VERSION_NAME=2.0.4 +VERSION_CODE=105 GROUP=it.sephiroth.android.library.targettooltip POM_DESCRIPTION=Custom tooltips for android diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index d30a0762..ee3e0c69 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Wed Jan 16 15:11:44 EST 2019 +#Fri Jan 25 16:35:02 EST 2019 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.1-milestone-1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip diff --git a/xtooltip/src/main/java/it/sephiroth/android/library/xtooltip/Tooltip.kt b/xtooltip/src/main/java/it/sephiroth/android/library/xtooltip/Tooltip.kt index ff0d086b..94cb1e43 100644 --- a/xtooltip/src/main/java/it/sephiroth/android/library/xtooltip/Tooltip.kt +++ b/xtooltip/src/main/java/it/sephiroth/android/library/xtooltip/Tooltip.kt @@ -13,6 +13,7 @@ import android.view.* import android.view.ViewGroup import android.view.ViewGroup.LayoutParams.WRAP_CONTENT import android.view.animation.AccelerateDecelerateInterpolator +import android.view.animation.AnimationUtils import android.widget.FrameLayout import android.widget.PopupWindow.INPUT_METHOD_NOT_NEEDED import android.widget.TextView @@ -81,6 +82,8 @@ class Tooltip private constructor(private val context: Context, builder: Builder private var mHasAnchorView = false private var mFollowAnchor = false private var mAnimationStyleResId: Int + private var mEnterAnimation: Int + private var mExitAnimation: Int private var mTextStyleResId: Int private var mViewOverlay: TooltipOverlay? = null @@ -153,6 +156,10 @@ class Tooltip private constructor(private val context: Context, builder: Builder theme.getResourceId(R.styleable.TooltipLayout_ttlm_animationStyle, android.R.style.Animation_Toast) } + val typedArray = context.theme.obtainStyledAttributes(mAnimationStyleResId, intArrayOf(android.R.attr.windowEnterAnimation, android.R.attr.windowExitAnimation)) + mEnterAnimation = typedArray.getResourceId(typedArray.getIndex(0), 0) + mExitAnimation = typedArray.getResourceId(typedArray.getIndex(1), 0) + typedArray.recycle() val font = theme.getString(R.styleable.TooltipLayout_ttlm_font) @@ -249,7 +256,7 @@ class Tooltip private constructor(private val context: Context, builder: Builder p.token = token p.softInputMode = mSoftInputMode p.title = "ToolTip:" + Integer.toHexString(hashCode()) - p.windowAnimations = mAnimationStyleResId +// p.windowAnimations = mAnimationStyleResId return p } @@ -661,6 +668,11 @@ class Tooltip private constructor(private val context: Context, builder: Builder private fun fadeIn() { if (!isShowing || isVisible) return + if (mEnterAnimation != 0) { + mTextView.clearAnimation() + mTextView.startAnimation(AnimationUtils.loadAnimation(context, mEnterAnimation)) + } + isVisible = true mShownFunc?.invoke(this) } @@ -668,9 +680,25 @@ class Tooltip private constructor(private val context: Context, builder: Builder private fun fadeOut() { if (!isShowing || !isVisible) return - isVisible = false - removeCallbacks() - dismiss() + if (mExitAnimation != 0) { + val animation = AnimationUtils.loadAnimation(context, mExitAnimation) + animation.setListener { + onAnimationEnd { + isVisible = false + removeCallbacks() + dismiss() + } + }.start() + + mTextView.clearAnimation() + mTextView.startAnimation(animation) + + } else { + isVisible = false + removeCallbacks() + dismiss() + } + } inner class TooltipViewContainer(context: Context) : FrameLayout(context) { diff --git a/xtooltip/src/main/java/it/sephiroth/android/library/xtooltip/Utils.kt b/xtooltip/src/main/java/it/sephiroth/android/library/xtooltip/Utils.kt index 7c1549a4..45a75bfb 100644 --- a/xtooltip/src/main/java/it/sephiroth/android/library/xtooltip/Utils.kt +++ b/xtooltip/src/main/java/it/sephiroth/android/library/xtooltip/Utils.kt @@ -4,6 +4,7 @@ import android.animation.Animator import android.graphics.Rect import android.view.View import android.view.ViewPropertyAnimator +import android.view.animation.Animation /** * Created by alessandro crugnola on 12/12/15. @@ -56,16 +57,54 @@ internal class AttachStateChangeListener : View.OnAttachStateChangeListener { } internal inline fun ViewPropertyAnimator.setListener( - func: AnimationListener.() -> Unit - ): ViewPropertyAnimator { - val listener = AnimationListener() + func: ViewPropertyAnimatorListener.() -> Unit +): ViewPropertyAnimator { + val listener = ViewPropertyAnimatorListener() listener.func() setListener(listener) return this } +internal inline fun Animation.setListener(func: AnimationListener.() -> Unit): Animation { + val listener = AnimationListener() + listener.func() + setAnimationListener(listener) + return this +} + +internal class AnimationListener : Animation.AnimationListener { + private var _onAnimationRepeat: ((animation: Animation?) -> Unit)? = null + private var _onAnimationEnd: ((animation: Animation?) -> Unit)? = null + private var _onAnimationStart: ((animation: Animation?) -> Unit)? = null + + override fun onAnimationRepeat(animation: Animation?) { + _onAnimationRepeat?.invoke(animation) + } + + override fun onAnimationEnd(animation: Animation?) { + _onAnimationEnd?.invoke(animation) + } + + override fun onAnimationStart(animation: Animation?) { + _onAnimationStart?.invoke(animation) + } + + fun onAnimationEnd(func: (animation: Animation?) -> Unit) { + _onAnimationEnd = func + } + + fun onAnimationRepeat(func: (animation: Animation?) -> Unit) { + _onAnimationRepeat = func + } + + fun onAnimationStart(func: (animation: Animation?) -> Unit) { + _onAnimationStart = func + } + +} + @Suppress("unused") -internal class AnimationListener : Animator.AnimatorListener { +internal class ViewPropertyAnimatorListener : Animator.AnimatorListener { private var _onAnimationRepeat: ((animation: Animator) -> Unit)? = null private var _onAnimationEnd: ((animation: Animator) -> Unit)? = null private var _onAnimationStart: ((animation: Animator) -> Unit)? = null