From 29ca9bc4a18b7938372c703d12fd76efbc4524a3 Mon Sep 17 00:00:00 2001 From: Alessandro Crugnola Date: Fri, 18 Jan 2019 14:56:29 -0500 Subject: [PATCH 01/23] dependencies --- xtooltip/build.gradle | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/xtooltip/build.gradle b/xtooltip/build.gradle index 4450e711..5d17f0c5 100644 --- a/xtooltip/build.gradle +++ b/xtooltip/build.gradle @@ -33,15 +33,15 @@ android { dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation 'androidx.appcompat:appcompat:1.0.1' + implementation 'androidx.appcompat:appcompat:1.0.2' implementation 'androidx.core:core-ktx:1.0.1' implementation 'com.jakewharton.timber:timber:4.7.1' implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" - testImplementation "androidx.test.ext:junit:1.0.0" + testImplementation "androidx.test.ext:junit:1.1.0" - androidTestImplementation "androidx.test.ext:junit:1.0.0" - androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0' + androidTestImplementation "androidx.test.ext:junit:1.1.0" + androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' } apply from: 'https://raw.githubusercontent.com/sephiroth74/gradle-mvn-push/master/gradle-mvn-push.gradle' \ No newline at end of file From e6a83ce52e98b8612d4d5e1f6891bb9593057f13 Mon Sep 17 00:00:00 2001 From: Alessandro Crugnola Date: Fri, 18 Jan 2019 14:56:47 -0500 Subject: [PATCH 02/23] using floats --- .../library/xtooltip/TooltipTextDrawable.kt | 60 +++++++++---------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/xtooltip/src/main/java/it/sephiroth/android/library/xtooltip/TooltipTextDrawable.kt b/xtooltip/src/main/java/it/sephiroth/android/library/xtooltip/TooltipTextDrawable.kt index 94eb3443..ecae3552 100644 --- a/xtooltip/src/main/java/it/sephiroth/android/library/xtooltip/TooltipTextDrawable.kt +++ b/xtooltip/src/main/java/it/sephiroth/android/library/xtooltip/TooltipTextDrawable.kt @@ -30,13 +30,13 @@ import kotlin.math.floor internal class TooltipTextDrawable(context: Context, builder: Tooltip.Builder) : Drawable() { private val rectF: RectF private val path: Path - private val tmpPoint = Point() + private val tmpPoint = PointF() private val outlineRect = Rect() private val bgPaint: Paint? private val stPaint: Paint? private val arrowRatio: Float private val radius: Float - private var point: Point? = null + private var point: PointF? = null private var padding = 0 private var arrowWeight = 0 private var gravity: Tooltip.Gravity? = null @@ -44,10 +44,10 @@ internal class TooltipTextDrawable(context: Context, builder: Tooltip.Builder) : init { val theme = context.theme.obtainStyledAttributes( - null, - R.styleable.TooltipLayout, - builder.defStyleAttr, - builder.defStyleRes + null, + R.styleable.TooltipLayout, + builder.defStyleAttr, + builder.defStyleRes ) this.radius = theme.getDimensionPixelSize(R.styleable.TooltipLayout_ttlm_cornerRadius, 4).toFloat() val strokeWidth = theme.getDimensionPixelSize(R.styleable.TooltipLayout_ttlm_strokeWeight, 2) @@ -88,7 +88,7 @@ internal class TooltipTextDrawable(context: Context, builder: Tooltip.Builder) : } } - fun setAnchor(gravity: Tooltip.Gravity, padding: Int, point: Point?) { + fun setAnchor(gravity: Tooltip.Gravity, padding: Int, point: PointF?) { Timber.i("setAnchor($gravity, $padding, $point)") if (gravity != this.gravity || padding != this.padding || !ObjectsCompat.equals(this.point, point)) { this.gravity = gravity @@ -96,7 +96,7 @@ internal class TooltipTextDrawable(context: Context, builder: Tooltip.Builder) : this.arrowWeight = (padding.toFloat() / arrowRatio).toInt() point?.let { - this.point = Point(it) + this.point = PointF(it.x, it.y) } ?: run { this.point = null } @@ -129,15 +129,15 @@ internal class TooltipTextDrawable(context: Context, builder: Tooltip.Builder) : } private fun calculatePathWithGravity( - outBounds: Rect, - left: Int, - top: Int, - right: Int, - bottom: Int, - maxY: Float, - maxX: Float, - minY: Float, - minX: Float + outBounds: Rect, + left: Int, + top: Int, + right: Int, + bottom: Int, + maxY: Float, + maxX: Float, + minY: Float, + minX: Float ) { if (gravity == Tooltip.Gravity.LEFT || gravity == Tooltip.Gravity.RIGHT) { @@ -153,7 +153,7 @@ internal class TooltipTextDrawable(context: Context, builder: Tooltip.Builder) : } val drawPoint = - isDrawPoint(left, top, right, bottom, maxY, maxX, minY, minX, tmpPoint, point!!, gravity, arrowWeight) + isDrawPoint(left, top, right, bottom, maxY, maxX, minY, minX, tmpPoint, point!!, gravity, arrowWeight) Timber.v("drawPoint: $drawPoint, point: $point, tmpPoint: $tmpPoint") @@ -240,9 +240,9 @@ internal class TooltipTextDrawable(context: Context, builder: Tooltip.Builder) : const val ARROW_RATIO_DEFAULT = 1.4f private fun isDrawPoint( - left: Int, top: Int, right: Int, bottom: Int, maxY: Float, maxX: Float, minY: Float, - minX: Float, tmpPoint: Point, point: Point, gravity: Tooltip.Gravity?, - arrowWeight: Int + left: Int, top: Int, right: Int, bottom: Int, maxY: Float, maxX: Float, minY: Float, + minX: Float, tmpPoint: PointF, point: PointF, gravity: Tooltip.Gravity?, + arrowWeight: Int ): Boolean { Timber.i("isDrawPoint: Rect($left, $top, $right, $bottom), x: [$minX, $maxX], y: [$minY, $maxY], point: $point, $arrowWeight") var drawPoint = false @@ -251,9 +251,9 @@ internal class TooltipTextDrawable(context: Context, builder: Tooltip.Builder) : if (gravity == Tooltip.Gravity.RIGHT || gravity == Tooltip.Gravity.LEFT) { if (tmpPoint.y in top..bottom) { if (top + tmpPoint.y + arrowWeight > maxY) { - tmpPoint.y = (maxY - arrowWeight.toFloat() - top.toFloat()).toInt() + tmpPoint.y = (maxY - arrowWeight.toFloat() - top.toFloat()) } else if (top + tmpPoint.y - arrowWeight < minY) { - tmpPoint.y = (minY + arrowWeight - top).toInt() + tmpPoint.y = (minY + arrowWeight - top) } drawPoint = true } @@ -261,9 +261,9 @@ internal class TooltipTextDrawable(context: Context, builder: Tooltip.Builder) : if (tmpPoint.x in left..right) { if (tmpPoint.x in left..right) { if (left + tmpPoint.x + arrowWeight > maxX) { - tmpPoint.x = (maxX - arrowWeight.toFloat() - left.toFloat()).toInt() + tmpPoint.x = (maxX - arrowWeight.toFloat() - left.toFloat()) } else if (left + tmpPoint.x - arrowWeight < minX) { - tmpPoint.x = (minX + arrowWeight - left).toInt() + tmpPoint.x = (minX + arrowWeight - left) } drawPoint = true } @@ -273,17 +273,17 @@ internal class TooltipTextDrawable(context: Context, builder: Tooltip.Builder) : return drawPoint } - private fun clampPoint(left: Int, top: Int, right: Int, bottom: Int, tmpPoint: Point) { + private fun clampPoint(left: Int, top: Int, right: Int, bottom: Int, tmpPoint: PointF) { if (tmpPoint.y < top) { - tmpPoint.y = top + tmpPoint.y = top.toFloat() } else if (tmpPoint.y > bottom) { - tmpPoint.y = bottom + tmpPoint.y = bottom.toFloat() } if (tmpPoint.x < left) { - tmpPoint.x = left + tmpPoint.x = left.toFloat() } if (tmpPoint.x > right) { - tmpPoint.x = right + tmpPoint.x = right.toFloat() } } } From 3a8e9ab8d0f25643b017542f6b3a7cb77353fe48 Mon Sep 17 00:00:00 2001 From: Alessandro Crugnola Date: Fri, 18 Jan 2019 14:57:16 -0500 Subject: [PATCH 03/23] update position and text --- .../android/library/xtooltip/Tooltip.kt | 217 +++++++++++------- 1 file changed, 140 insertions(+), 77 deletions(-) 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 4cffaf89..63d3a7ac 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 @@ -4,10 +4,7 @@ import android.animation.ObjectAnimator import android.animation.ValueAnimator import android.annotation.SuppressLint import android.content.Context -import android.graphics.PixelFormat -import android.graphics.Point -import android.graphics.Rect -import android.graphics.Typeface +import android.graphics.* import android.os.Build import android.os.Handler import android.os.IBinder @@ -49,7 +46,7 @@ import java.util.* class Tooltip private constructor(private val context: Context, builder: Builder) { private val windowManager: WindowManager = - context.getSystemService(Context.WINDOW_SERVICE) as WindowManager + context.getSystemService(Context.WINDOW_SERVICE) as WindowManager var isShowing = false private set @@ -115,10 +112,13 @@ class Tooltip private constructor(private val context: Context, builder: Builder if (mOldLocation!![0] != mNewLocation[1] || mOldLocation!![1] != mNewLocation[1]) { offsetBy( - mNewLocation[0] - mOldLocation!![0], - mNewLocation[1] - mOldLocation!![1] + (mNewLocation[0] - mOldLocation!![0]).toFloat(), + (mNewLocation[1] - mOldLocation!![1]).toFloat() ) } + + mOldLocation!![0] = mNewLocation[0] + mOldLocation!![1] = mNewLocation[1] } } } @@ -127,25 +127,25 @@ class Tooltip private constructor(private val context: Context, builder: Builder init { val theme = context.theme - .obtainStyledAttributes( - null, - R.styleable.TooltipLayout, - builder.defStyleAttr, - builder.defStyleRes - ) + .obtainStyledAttributes( + null, + R.styleable.TooltipLayout, + builder.defStyleAttr, + builder.defStyleRes + ) this.mPadding = theme.getDimensionPixelSize(R.styleable.TooltipLayout_ttlm_padding, 30) this.mTextAppearance = theme.getResourceId(R.styleable.TooltipLayout_android_textAppearance, 0) this.mTextGravity = theme - .getInt( - R.styleable.TooltipLayout_android_gravity, - android.view.Gravity.TOP or android.view.Gravity.START - ) + .getInt( + R.styleable.TooltipLayout_android_gravity, + android.view.Gravity.TOP or android.view.Gravity.START + ) this.mTextViewElevation = theme.getDimension(R.styleable.TooltipLayout_ttlm_elevation, 0f) mOverlayStyle = theme.getResourceId( - R.styleable.TooltipLayout_ttlm_overlayStyle, - R.style.ToolTipOverlayDefaultStyle + R.styleable.TooltipLayout_ttlm_overlayStyle, + R.style.ToolTipOverlayDefaultStyle ) val font = theme.getString(R.styleable.TooltipLayout_ttlm_font) theme.recycle() @@ -203,6 +203,26 @@ class Tooltip private constructor(private val context: Context, builder: Builder return this } + fun update(text: CharSequence) { + if (isShowing && null != mPopupView) { + + var currentWidth = mContentView.width + + mTextView.text = if (text is Spannable) { + mText + } else { + @Suppress("DEPRECATION") + Html.fromHtml(text as String) + } + + // if following, need to update based on its content + } + } + + fun update(@StringRes res: Int) { + update(context.resources.getString(res)) + } + @SuppressLint("RtlHardcoded") private fun createPopupLayoutParams(token: IBinder): WindowManager.LayoutParams { val p = WindowManager.LayoutParams() @@ -255,14 +275,14 @@ class Tooltip private constructor(private val context: Context, builder: Builder with(mViewOverlay!!) { adjustViewBounds = true layoutParams = ViewGroup.LayoutParams( - ViewGroup.LayoutParams.WRAP_CONTENT, - ViewGroup.LayoutParams.WRAP_CONTENT + ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.WRAP_CONTENT ) } } val contentView = - LayoutInflater.from(context).inflate(mTooltipLayoutIdRes, viewContainer, false) + LayoutInflater.from(context).inflate(mTooltipLayoutIdRes, viewContainer, false) mFloatingAnimation?.let { contentView.setPadding(it.radius) } @@ -301,8 +321,8 @@ class Tooltip private constructor(private val context: Context, builder: Builder if (null != mViewOverlay) { viewContainer.addView( - mViewOverlay, - FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT) + mViewOverlay, + FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT) ) } @@ -339,12 +359,12 @@ class Tooltip private constructor(private val context: Context, builder: Builder } private fun findPosition( - parent: View, - anchor: View?, - offset: Point, - gravities: ArrayList, - params: WindowManager.LayoutParams, - fitToScreen: Boolean = false + parent: View, + anchor: View?, + offset: Point, + gravities: ArrayList, + params: WindowManager.LayoutParams, + fitToScreen: Boolean = false ): Positions? { if (null == mPopupView) return null @@ -356,7 +376,7 @@ class Tooltip private constructor(private val context: Context, builder: Builder val displayFrame = Rect() val anchorPosition = intArrayOf(0, 0) - val centerPosition = Point(offset) + val centerPosition = PointF(offset) parent.getWindowVisibleDisplayFrame(displayFrame) @@ -452,10 +472,10 @@ class Tooltip private constructor(private val context: Context, builder: Builder if (fitToScreen) { val finalRect = Rect( - contentPosition.x, - contentPosition.y, - contentPosition.x + w, - contentPosition.y + h + contentPosition.x, + contentPosition.y, + contentPosition.x + w, + contentPosition.y + h ) if (!displayFrame.rectContainsWithTolerance(finalRect, mSizeTolerance.toInt())) { Timber.e("content won't fit! $displayFrame, $finalRect") @@ -463,7 +483,7 @@ class Tooltip private constructor(private val context: Context, builder: Builder } } - return Positions(displayFrame, arrowPosition, centerPosition, contentPosition, gravity, params) + return Positions(displayFrame, PointF(arrowPosition), centerPosition, PointF(contentPosition), gravity, params) } private var mCurrentPosition: Positions? = null @@ -482,12 +502,12 @@ class Tooltip private constructor(private val context: Context, builder: Builder } mDrawable?.setAnchor( - it.gravity, - if (!mShowArrow) 0 else mPadding / 2, - if (!mShowArrow) null else Point(it.arrowPointX, it.arrowPointY) + it.gravity, + if (!mShowArrow) 0 else mPadding / 2, + if (!mShowArrow) null else PointF(it.arrowPointX, it.arrowPointY) ) - offsetBy(0, 0) + offsetBy(0f, 0f) it.params.packageName = context.packageName mPopupView?.fitsSystemWindows = mLayoutInsetDecor @@ -502,16 +522,40 @@ class Tooltip private constructor(private val context: Context, builder: Builder } @Suppress("SpellCheckingInspection") - private fun offsetBy(xoff: Int, yoff: Int) { + fun offsetBy(xoff: Float, yoff: Float) { if (isShowing && mPopupView != null && mCurrentPosition != null) { Timber.i("offsetBy($xoff, $yoff)") + Timber.v("current: ${mCurrentPosition!!.contentPointX}") + + mCurrentPosition!!.offsetBy(xoff, yoff) - mContentView.translationX = mCurrentPosition!!.contentPointX.toFloat() + xoff - mContentView.translationY = mCurrentPosition!!.contentPointY.toFloat() + yoff + Timber.v("new: ${mCurrentPosition!!.contentPointX}") + + mContentView.translationX = mCurrentPosition!!.contentPointX + mContentView.translationY = mCurrentPosition!!.contentPointY + + mViewOverlay?.let { viewOverlay -> + viewOverlay.translationX = mCurrentPosition!!.centerPointX - viewOverlay.measuredWidth / 2 + viewOverlay.translationY = mCurrentPosition!!.centerPointY - viewOverlay.measuredHeight / 2 + } + } + } + + fun offsetTo(x: Float, y: Float) { + if (isShowing && mPopupView != null && mCurrentPosition != null) { + Timber.i("offsetTo($x, $y)") + Timber.v("current: ${mCurrentPosition!!.contentPointX}") + + mCurrentPosition!!.offsetTo(x, y) + + Timber.v("new: ${mCurrentPosition!!.contentPointX}") + + mContentView.translationX = mCurrentPosition!!.contentPointX + mContentView.translationY = mCurrentPosition!!.contentPointY mViewOverlay?.let { viewOverlay -> - viewOverlay.translationX = mCurrentPosition!!.centerPointX.toFloat() - viewOverlay.measuredWidth / 2 + xoff - viewOverlay.translationY = mCurrentPosition!!.centerPointY.toFloat() - viewOverlay.measuredHeight / 2 + yoff + viewOverlay.translationX = mCurrentPosition!!.centerPointX - viewOverlay.measuredWidth / 2 + viewOverlay.translationY = mCurrentPosition!!.centerPointY - viewOverlay.measuredHeight / 2 } } } @@ -574,14 +618,14 @@ class Tooltip private constructor(private val context: Context, builder: Builder gravities.add(0, gravity) invokePopup( - findPosition( - parent, - mAnchorView?.get(), - mAnchorPoint, - gravities, - params, - fitToScreen - ) + findPosition( + parent, + mAnchorView?.get(), + mAnchorPoint, + gravities, + params, + fitToScreen + ) ) } @@ -618,8 +662,8 @@ class Tooltip private constructor(private val context: Context, builder: Builder if (fadeDuration > 0 && null != mPopupView) { mPopupView!!.alpha = 0F mPopupView!!.animate() - .setDuration(mFadeDuration) - .alpha(1f).start() + .setDuration(mFadeDuration) + .alpha(1f).start() } mShownFunc?.invoke(this) } @@ -636,15 +680,15 @@ class Tooltip private constructor(private val context: Context, builder: Builder mPopupView?.let { popupView -> popupView.clearAnimation() popupView.animate() - .alpha(0f) - .setDuration(fadeDuration) - .setListener { - onAnimationEnd { - popupView.visibility = View.INVISIBLE - dismiss() - } + .alpha(0f) + .setDuration(fadeDuration) + .setListener { + onAnimationEnd { + popupView.visibility = View.INVISIBLE + dismiss() } - .start() + } + .start() } } else { dismiss() @@ -725,21 +769,40 @@ class Tooltip private constructor(private val context: Context, builder: Builder } private data class Positions( - val displayFrame: Rect, - val arrowPoint: Point, - val centerPoint: Point, - val contentPoint: Point, - val gravity: Gravity, - val params: WindowManager.LayoutParams + val displayFrame: Rect, + val arrowPoint: PointF, + val centerPoint: PointF, + val contentPoint: PointF, + val gravity: Gravity, + val params: WindowManager.LayoutParams ) { - val centerPointX: Int = centerPoint.x - val centerPointY: Int = centerPoint.y// - displayFrame.top - - val arrowPointX: Int = arrowPoint.x - val arrowPointY: Int = arrowPoint.y// - displayFrame.top - - val contentPointX: Int = contentPoint.x - val contentPointY: Int = contentPoint.y// - displayFrame.top + fun offsetBy(x: Float, y: Float) { + centerPoint.offset(x, y) + contentPoint.offset(x, y) + arrowPoint.offset(x, y) + } + + fun offsetTo(x: Float, y: Float) { + val dx = x - contentPoint.x + val dy = y - contentPoint.y + + contentPoint.offset(dx, dy) + centerPoint.offset(dx, dy) + arrowPoint.offset(dx, dy) + } + + var centerPointX: Float = 0f + get() = centerPoint.x + var centerPointY: Float = 0f + get() = centerPoint.y // - displayFrame.top + var arrowPointX: Float = 0f + get() = arrowPoint.x + var arrowPointY: Float = 0f + get() = arrowPoint.y // - displayFrame.top + var contentPointX: Float = 0f + get () = contentPoint.x + var contentPointY: Float = 0f + get() = contentPoint.y // - displayFrame.top } enum class Gravity { From 397c6bd6d4aa96ef1752a3a30b4cfd5b30948ecb Mon Sep 17 00:00:00 2001 From: Alessandro Crugnola Date: Sun, 20 Jan 2019 21:28:13 +0100 Subject: [PATCH 04/23] using animation style instead of fadeDuration --- xtooltip/build.gradle | 4 +- .../android/library/xtooltip/Tooltip.kt | 49 ++++--------------- xtooltip/src/main/res/layout/textview.xml | 4 +- xtooltip/src/main/res/values/attrs.xml | 1 + xtooltip/src/main/res/values/styles.xml | 1 + 5 files changed, 17 insertions(+), 42 deletions(-) diff --git a/xtooltip/build.gradle b/xtooltip/build.gradle index 5d17f0c5..8e7716f5 100644 --- a/xtooltip/build.gradle +++ b/xtooltip/build.gradle @@ -44,4 +44,6 @@ dependencies { androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' } -apply from: 'https://raw.githubusercontent.com/sephiroth74/gradle-mvn-push/master/gradle-mvn-push.gradle' \ No newline at end of file +try { + apply from: 'https://raw.githubusercontent.com/sephiroth74/gradle-mvn-push/master/gradle-mvn-push.gradle' +} catch(e) {} \ No newline at end of file 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 63d3a7ac..98565a6e 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 @@ -66,7 +66,6 @@ class Tooltip private constructor(private val context: Context, builder: Builder private var mPadding: Int = 0 private var mActivateDelay: Long private var mClosePolicy: ClosePolicy - private var mFadeDuration: Long private var mShowDuration: Long private var mMaxWidth: Int? = null private var mTextAppearance: Int @@ -83,6 +82,7 @@ class Tooltip private constructor(private val context: Context, builder: Builder private var mActivated = false private var mHasAnchorView = false private var mFollowAnchor = false + private var mAnimationStyleResId: Int private var mViewOverlay: TooltipOverlay? = null private var mDrawable: TooltipTextDrawable? = null @@ -147,6 +147,9 @@ class Tooltip private constructor(private val context: Context, builder: Builder R.styleable.TooltipLayout_ttlm_overlayStyle, R.style.ToolTipOverlayDefaultStyle ) + mAnimationStyleResId = + theme.getResourceId(R.styleable.TooltipLayout_ttlm_animationStyle, R.style.Animation_AppCompat_Tooltip) + val font = theme.getString(R.styleable.TooltipLayout_ttlm_font) theme.recycle() @@ -157,7 +160,6 @@ class Tooltip private constructor(private val context: Context, builder: Builder this.mMaxWidth = builder.maxWidth this.mFloatingAnimation = builder.floatingAnimation this.mShowDuration = builder.showDuration - this.mFadeDuration = builder.fadeDuration this.mShowOverlay = builder.overlay this.mShowArrow = builder.showArrow && builder.layoutId == null builder.anchorView?.let { @@ -235,6 +237,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 return p } @@ -513,7 +516,7 @@ class Tooltip private constructor(private val context: Context, builder: Builder mPopupView?.fitsSystemWindows = mLayoutInsetDecor windowManager.addView(mPopupView, it.params) Timber.v("windowManager.addView: $mPopupView") - fadeIn(mFadeDuration) + fadeIn() return this } ?: run { mFailureFunc?.invoke(this) @@ -632,7 +635,7 @@ class Tooltip private constructor(private val context: Context, builder: Builder fun hide() { Timber.i("hide") if (!isShowing) return - fadeOut(mFadeDuration) + fadeOut() } fun dismiss() { @@ -654,45 +657,19 @@ class Tooltip private constructor(private val context: Context, builder: Builder mHandler.removeCallbacks(activateRunnable) } - private fun fadeIn(fadeDuration: Long) { + private fun fadeIn() { if (!isShowing || isVisible) return isVisible = true - - if (fadeDuration > 0 && null != mPopupView) { - mPopupView!!.alpha = 0F - mPopupView!!.animate() - .setDuration(mFadeDuration) - .alpha(1f).start() - } mShownFunc?.invoke(this) } - private fun fadeOut(fadeDuration: Long) { + private fun fadeOut() { if (!isShowing || !isVisible) return isVisible = false removeCallbacks() - - Timber.i("fadeOut($fadeDuration)") - - if (fadeDuration > 0) { - mPopupView?.let { popupView -> - popupView.clearAnimation() - popupView.animate() - .alpha(0f) - .setDuration(fadeDuration) - .setListener { - onAnimationEnd { - popupView.visibility = View.INVISIBLE - dismiss() - } - } - .start() - } - } else { - dismiss() - } + dismiss() } inner class TooltipViewContainer(context: Context) : FrameLayout(context) { @@ -831,7 +808,6 @@ class Tooltip private constructor(private val context: Context, builder: Builder internal var overlay = true internal var floatingAnimation: Animation? = null internal var showDuration: Long = 0 - internal var fadeDuration: Long = 100 internal var showArrow = true internal var activateDelay = 0L internal var followAnchor = false @@ -874,11 +850,6 @@ class Tooltip private constructor(private val context: Context, builder: Builder return this } - fun fadeDuration(value: Long): Builder { - this.fadeDuration = value - return this - } - fun showDuration(value: Long): Builder { this.showDuration = value return this diff --git a/xtooltip/src/main/res/layout/textview.xml b/xtooltip/src/main/res/layout/textview.xml index 81b92449..e49eca3b 100644 --- a/xtooltip/src/main/res/layout/textview.xml +++ b/xtooltip/src/main/res/layout/textview.xml @@ -13,8 +13,8 @@ diff --git a/xtooltip/src/main/res/values/attrs.xml b/xtooltip/src/main/res/values/attrs.xml index 5b20d3fa..0a1e2c58 100644 --- a/xtooltip/src/main/res/values/attrs.xml +++ b/xtooltip/src/main/res/values/attrs.xml @@ -15,6 +15,7 @@ + diff --git a/xtooltip/src/main/res/values/styles.xml b/xtooltip/src/main/res/values/styles.xml index 0016c19a..bae53f6f 100644 --- a/xtooltip/src/main/res/values/styles.xml +++ b/xtooltip/src/main/res/values/styles.xml @@ -11,6 +11,7 @@ ?android:attr/textAppearanceSmallInverse @style/ToolTipOverlayDefaultStyle @dimen/ttlm_default_elevation + @android:style/Animation.Toast + + @@ -31,4 +31,9 @@ 8dp + + \ No newline at end of file From 87435d82afbe3bf23109d2af41f8c4573aac8538 Mon Sep 17 00:00:00 2001 From: Alessandro Crugnola Date: Thu, 24 Jan 2019 07:52:12 -0500 Subject: [PATCH 10/23] git gravity --- .../library/tooltip_demo/MainActivity.kt | 18 ++++++++++++++++-- app/src/main/res/layout/content_main.xml | 2 +- .../android/library/xtooltip/Tooltip.kt | 4 ++++ 3 files changed, 21 insertions(+), 3 deletions(-) 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 eb46d889..0fe2ef8a 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 @@ -4,6 +4,7 @@ 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.xtooltip.ClosePolicy import it.sephiroth.android.library.xtooltip.Tooltip import it.sephiroth.android.library.xtooltip.Typefaces @@ -36,10 +37,23 @@ class MainActivity : AppCompatActivity() { Timber.v("gravity: $gravity") Timber.v("closePolicy: $closePolicy") - tooltip?.dismiss() +// 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 = Tooltip.Builder(this) - .anchor(button, -50, 0, false) + .anchor(button, 0, 0, false) .text(text) .styleId(style) .typeface(typeface) diff --git a/app/src/main/res/layout/content_main.xml b/app/src/main/res/layout/content_main.xml index 0d304a98..ca7bee04 100644 --- a/app/src/main/res/layout/content_main.xml +++ b/app/src/main/res/layout/content_main.xml @@ -155,7 +155,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_columnSpan="2" - android:hint="Tooltip Text" + android:hint="10" android:maxLines="2" /> 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 da8a5cef..499037e3 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 @@ -92,6 +92,10 @@ class Tooltip private constructor(private val context: Context, builder: Builder private val hideRunnable = Runnable { hide() } private val activateRunnable = Runnable { mActivated = true } + var gravity: Gravity? = null + get() = mCurrentPosition?.gravity + private set + var text: CharSequence? = null get() = mText private set From f3fa1bc6c717c6dd086aeac266530c3e66b5ab40 Mon Sep 17 00:00:00 2001 From: Alessandro Crugnola Date: Thu, 24 Jan 2019 07:58:17 -0500 Subject: [PATCH 11/23] correct offset --- .../java/it/sephiroth/android/library/xtooltip/Tooltip.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 499037e3..d3e5e9ef 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 @@ -736,8 +736,8 @@ class Tooltip private constructor(private val context: Context, builder: Builder var mOffsetY: Float = 0f fun offsetBy(x: Float, y: Float) { - mOffsetX = x - mOffsetY = y + mOffsetX += x + mOffsetY += y } var centerPointX: Float = 0f From d69f17ab5bcc20b3075c0729bb774ab320dc7530 Mon Sep 17 00:00:00 2001 From: Alessandro Crugnola Date: Fri, 25 Jan 2019 11:59:28 -0500 Subject: [PATCH 12/23] offsets --- .../android/library/xtooltip/Tooltip.kt | 45 +++++++++++++++---- 1 file changed, 36 insertions(+), 9 deletions(-) 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 d3e5e9ef..ff0d086b 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 @@ -121,7 +121,7 @@ class Tooltip private constructor(private val context: Context, builder: Builder offsetBy( (mNewLocation[0] - mOldLocation!![0]).toFloat(), (mNewLocation[1] - mOldLocation!![1]).toFloat() - ) + ) } mOldLocation!![0] = mNewLocation[0] @@ -134,12 +134,12 @@ class Tooltip private constructor(private val context: Context, builder: Builder init { val theme = context.theme - .obtainStyledAttributes( - null, - R.styleable.TooltipLayout, - builder.defStyleAttr, - builder.defStyleRes - ) + .obtainStyledAttributes( + null, + R.styleable.TooltipLayout, + builder.defStyleAttr, + builder.defStyleRes + ) this.mPadding = theme.getDimensionPixelSize(R.styleable.TooltipLayout_ttlm_padding, 30) mOverlayStyle = theme.getResourceId( @@ -482,7 +482,7 @@ class Tooltip private constructor(private val context: Context, builder: Builder contentPosition.y, contentPosition.x + w, contentPosition.y + h - ) + ) if (!displayFrame.rectContainsWithTolerance(finalRect, mSizeTolerance.toInt())) { Timber.e("content won't fit! $displayFrame, $finalRect") return findPosition(parent, anchor, offset, gravities, params, fitToScreen) @@ -541,6 +541,28 @@ class Tooltip private constructor(private val context: Context, builder: Builder } } + @Suppress("SpellCheckingInspection") + fun offsetTo(xoff: Float, yoff: Float) { + if (isShowing && mPopupView != null && mCurrentPosition != null) { + Timber.i("offsetTo($xoff, $yoff)") + mCurrentPosition!!.offsetTo(xoff, yoff) + + mContentView.translationX = mCurrentPosition!!.contentPointX + mContentView.translationY = mCurrentPosition!!.contentPointY + + mViewOverlay?.let { viewOverlay -> + viewOverlay.translationX = mCurrentPosition!!.centerPointX - viewOverlay.measuredWidth / 2 + viewOverlay.translationY = mCurrentPosition!!.centerPointY - viewOverlay.measuredHeight / 2 + } + } + } + + var offsetX: Float = 0f + get() = mCurrentPosition?.mOffsetX ?: kotlin.run { 0f } + + var offsetY: Float = 0f + get() = mCurrentPosition?.mOffsetY ?: kotlin.run { 0f } + private fun setupListeners(anchorView: View) { anchorView.addOnAttachStateChangeListener { onViewDetachedFromWindow { view: View?, listener: View.OnAttachStateChangeListener -> @@ -608,7 +630,7 @@ class Tooltip private constructor(private val context: Context, builder: Builder gravities, params, fitToScreen) - ) + ) } fun hide() { @@ -740,6 +762,11 @@ class Tooltip private constructor(private val context: Context, builder: Builder mOffsetY += y } + fun offsetTo(x: Float, y: Float) { + mOffsetX = x + mOffsetY = y + } + var centerPointX: Float = 0f get() = centerPoint.x + mOffsetX From 7b7e71c9255df633f16ae1cc25e74455f81a34b3 Mon Sep 17 00:00:00 2001 From: Alessandro Crugnola Date: Fri, 25 Jan 2019 14:49:48 -0500 Subject: [PATCH 13/23] travis --- .travis.yml | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index d2a0489b..4ac9399d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -42,11 +42,13 @@ before_script: # - $ANDROID_HOME/emulator/emulator -avd test -gpu swiftshader_indirect -no-audio -no-window -verbose & # - android-wait-for-emulator # - adb wait-for-device shell 'while [[ -z $(getprop sys.boot_completed) ]]; do sleep 1; done; input keyevent 82' - - mkdir -p "$ANDROID_HOME/licenses" || true - - cp ./licenses/* "$ANDROID_HOME/licenses" - - echo -e "\n8933bad161af4178b1185d1a37fbf41ea5269c55\nd56f5187479451eabf01fb78af6dfcb131a6481e" > "$ANDROID_HOME/licenses/android-sdk-license" - - echo -e "\n84831b9409646a918e30573bab4c9c91346d8abd\n504667f4c0de7af1a06de9f4b1727b84351f2910" > "$ANDROID_HOME/licenses/android-sdk-preview-license" - - echo "d56f5187479451eabf01fb78af6dfcb131a6481e" > "$ANDROID_HOME/licenses/android-sdk-license" + # - mkdir -p "$ANDROID_HOME/licenses" || true + # - cp ./licenses/* "$ANDROID_HOME/licenses" + # - echo -e "\n8933bad161af4178b1185d1a37fbf41ea5269c55\nd56f5187479451eabf01fb78af6dfcb131a6481e" > "$ANDROID_HOME/licenses/android-sdk-license" + # - echo -e "\n84831b9409646a918e30573bab4c9c91346d8abd\n504667f4c0de7af1a06de9f4b1727b84351f2910" > "$ANDROID_HOME/licenses/android-sdk-preview-license" + # - echo "d56f5187479451eabf01fb78af6dfcb131a6481e" > "$ANDROID_HOME/licenses/android-sdk-license" + - mkdir "$ANDROID_HOME/licenses" || true + - echo "d56f5187479451eabf01fb78af6dfcb131a6481e" > "$ANDROID_HOME/licenses/android-sdk-license" script: - adb logcat > logcat.log & From 4f3770ecf34b0e9f2fd04a04f5ce287e63d3a908 Mon Sep 17 00:00:00 2001 From: Alessandro Crugnola Date: Fri, 25 Jan 2019 14:56:48 -0500 Subject: [PATCH 14/23] travis --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 4ac9399d..e80f67f1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -49,6 +49,7 @@ before_script: # - echo "d56f5187479451eabf01fb78af6dfcb131a6481e" > "$ANDROID_HOME/licenses/android-sdk-license" - mkdir "$ANDROID_HOME/licenses" || true - echo "d56f5187479451eabf01fb78af6dfcb131a6481e" > "$ANDROID_HOME/licenses/android-sdk-license" + - echo "24333f8a63b6825ea9c5514f83c2829b004d1fee" > "$ANDROID_HOME/licenses/android-sdk-license" script: - adb logcat > logcat.log & From 759c5d0766a5f3b1bb93c50d82b42b9cba2d21bb Mon Sep 17 00:00:00 2001 From: Alessandro Crugnola Date: Fri, 25 Jan 2019 15:02:40 -0500 Subject: [PATCH 15/23] travis --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index e80f67f1..2b0540bc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -32,6 +32,7 @@ notifications: before_install: - sdkmanager tools - sdkmanager --update + - yes | sdkmanager --licenses - sdkmanager emulator - sdkmanager "system-images;android-25;google_apis;armeabi-v7a" - sdkmanager --update From 72c6478084d2a12b467f9bdefaa641c492e2ac7a Mon Sep 17 00:00:00 2001 From: Alessandro Crugnola Date: Fri, 25 Jan 2019 15:03:20 -0500 Subject: [PATCH 16/23] travis --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 2b0540bc..529f142f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -30,9 +30,9 @@ notifications: - alessandro.crugnola@gmail.com before_install: - - sdkmanager tools - sdkmanager --update - yes | sdkmanager --licenses + - sdkmanager tools - sdkmanager emulator - sdkmanager "system-images;android-25;google_apis;armeabi-v7a" - sdkmanager --update From 5582d0bd05e5add0d1f54a861bd1c99e4ed63cc5 Mon Sep 17 00:00:00 2001 From: Alessandro Crugnola Date: Fri, 25 Jan 2019 15:09:58 -0500 Subject: [PATCH 17/23] travis --- .travis.yml | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/.travis.yml b/.travis.yml index 529f142f..b2931694 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,21 +17,12 @@ android: - add-on - extra - licenses: - - 'android-sdk-license-.+' - - 'android-sdk-preview-license-.+' - - 'google-gdk-license-.+' - - 'intel-android-extra-license-.+' - - 'google-gdk-license-.+' - - 'android-googletv-license-.+' - notifications: email: - alessandro.crugnola@gmail.com before_install: - sdkmanager --update - - yes | sdkmanager --licenses - sdkmanager tools - sdkmanager emulator - sdkmanager "system-images;android-25;google_apis;armeabi-v7a" @@ -39,18 +30,8 @@ before_install: - echo no | avdmanager create avd --force -n test -k "system-images;android-25;google_apis;armeabi-v7a" --device "pixel" before_script: - # - $ANDROID_HOME/emulator/emulator -avd test -no-audio -skin 1440x2560 & - # - $ANDROID_HOME/emulator/emulator -avd test -gpu swiftshader_indirect -no-audio -no-window -verbose & - # - android-wait-for-emulator - # - adb wait-for-device shell 'while [[ -z $(getprop sys.boot_completed) ]]; do sleep 1; done; input keyevent 82' - # - mkdir -p "$ANDROID_HOME/licenses" || true - # - cp ./licenses/* "$ANDROID_HOME/licenses" - # - echo -e "\n8933bad161af4178b1185d1a37fbf41ea5269c55\nd56f5187479451eabf01fb78af6dfcb131a6481e" > "$ANDROID_HOME/licenses/android-sdk-license" - # - echo -e "\n84831b9409646a918e30573bab4c9c91346d8abd\n504667f4c0de7af1a06de9f4b1727b84351f2910" > "$ANDROID_HOME/licenses/android-sdk-preview-license" - # - echo "d56f5187479451eabf01fb78af6dfcb131a6481e" > "$ANDROID_HOME/licenses/android-sdk-license" - mkdir "$ANDROID_HOME/licenses" || true - - echo "d56f5187479451eabf01fb78af6dfcb131a6481e" > "$ANDROID_HOME/licenses/android-sdk-license" - - echo "24333f8a63b6825ea9c5514f83c2829b004d1fee" > "$ANDROID_HOME/licenses/android-sdk-license" + - echo "24333f8a63b6825ea9c5514f83c2829b004d1fee" > "$ANDROID_HOME/licenses/android-sdk-license" script: - adb logcat > logcat.log & From a91c9c7b38dd7564987bca16466992d98bba3722 Mon Sep 17 00:00:00 2001 From: Alessandro Crugnola Date: Fri, 25 Jan 2019 15:16:53 -0500 Subject: [PATCH 18/23] no message --- .travis.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index b2931694..4c544823 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,11 +22,7 @@ notifications: - alessandro.crugnola@gmail.com before_install: - - sdkmanager --update - - sdkmanager tools - - sdkmanager emulator - sdkmanager "system-images;android-25;google_apis;armeabi-v7a" - - sdkmanager --update - echo no | avdmanager create avd --force -n test -k "system-images;android-25;google_apis;armeabi-v7a" --device "pixel" before_script: From 60a3fc8e216a791539be29ebf03dd589bed8a505 Mon Sep 17 00:00:00 2001 From: Alessandro Crugnola Date: Fri, 25 Jan 2019 15:26:12 -0500 Subject: [PATCH 19/23] no message --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index 4c544823..5ab3e40b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,6 +10,8 @@ env: android: components: + - tools + - tools - build-tools-28.0.3 - android-25 - extra-android-m2repository @@ -27,6 +29,7 @@ before_install: before_script: - mkdir "$ANDROID_HOME/licenses" || true + - echo -e "\n8933bad161af4178b1185d1a37fbf41ea5269c55\nd56f5187479451eabf01fb78af6dfcb131a6481e" > "$ANDROID_HOME/licenses/android-sdk-license" - echo "24333f8a63b6825ea9c5514f83c2829b004d1fee" > "$ANDROID_HOME/licenses/android-sdk-license" script: From 08ae42ad429d9d671699822cddec780475c56ace Mon Sep 17 00:00:00 2001 From: Alessandro Crugnola Date: Fri, 25 Jan 2019 15:28:41 -0500 Subject: [PATCH 20/23] no message --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 5ab3e40b..8e8da519 100644 --- a/.travis.yml +++ b/.travis.yml @@ -24,6 +24,7 @@ notifications: - alessandro.crugnola@gmail.com before_install: + - yes | sdkmanager "platforms;android-28" - sdkmanager "system-images;android-25;google_apis;armeabi-v7a" - echo no | avdmanager create avd --force -n test -k "system-images;android-25;google_apis;armeabi-v7a" --device "pixel" From 1da3a4b1288ce7ac7386a088995420be1894f3ba Mon Sep 17 00:00:00 2001 From: Alessandro Crugnola Date: Fri, 25 Jan 2019 15:38:31 -0500 Subject: [PATCH 21/23] no message --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 8e8da519..a6150992 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,7 +26,7 @@ notifications: before_install: - yes | sdkmanager "platforms;android-28" - sdkmanager "system-images;android-25;google_apis;armeabi-v7a" - - echo no | avdmanager create avd --force -n test -k "system-images;android-25;google_apis;armeabi-v7a" --device "pixel" + - echo no | $ANDROID_HOME/tools/bin/avdmanager create avd --force -n test -k "system-images;android-25;google_apis;armeabi-v7a" --device "pixel" before_script: - mkdir "$ANDROID_HOME/licenses" || true From d6daf0e629b06be635a2821fc31a49f868dcaaaf Mon Sep 17 00:00:00 2001 From: Alessandro Crugnola Date: Fri, 25 Jan 2019 15:54:45 -0500 Subject: [PATCH 22/23] no message --- .travis.yml | 45 +++++++++++++++------------------------------ 1 file changed, 15 insertions(+), 30 deletions(-) diff --git a/.travis.yml b/.travis.yml index a6150992..7cbec755 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,51 +1,36 @@ language: android jdk: - - oraclejdk8 - -env: - global: - # install timeout in minutes (2 minutes by default) - - ADB_INSTALL_TIMEOUT=16 + - oraclejdk8 android: components: - tools - tools - build-tools-28.0.3 - - android-25 - - extra-android-m2repository - - extra-android-suppor - - add-on - - extra - -notifications: - email: - - alessandro.crugnola@gmail.com - -before_install: - - yes | sdkmanager "platforms;android-28" - - sdkmanager "system-images;android-25;google_apis;armeabi-v7a" - - echo no | $ANDROID_HOME/tools/bin/avdmanager create avd --force -n test -k "system-images;android-25;google_apis;armeabi-v7a" --device "pixel" + - platform-tools before_script: - mkdir "$ANDROID_HOME/licenses" || true - - echo -e "\n8933bad161af4178b1185d1a37fbf41ea5269c55\nd56f5187479451eabf01fb78af6dfcb131a6481e" > "$ANDROID_HOME/licenses/android-sdk-license" - echo "24333f8a63b6825ea9c5514f83c2829b004d1fee" > "$ANDROID_HOME/licenses/android-sdk-license" -script: - - adb logcat > logcat.log & - - ./gradlew clean build lint assemble - # - ./gradlew app:connectedCheck - -after_script: - - cat logcat.log +before_install: + - yes | sdkmanager "platforms;android-28" -after_failure: - - cat logcat.log +notifications: + email: + - alessandro.crugnola@gmail.com +cache: false sudo: false +install: + - chmod +x ./gradlew; ls -l gradlew; ./gradlew wrapper -v + +script: + - ./gradlew clean build lint assemble + cache: directories: + - $HOME/.m2 - $HOME/.gradle From dafe1a7338b5042d7df593e448d9971eca37b395 Mon Sep 17 00:00:00 2001 From: Alessandro Crugnola Date: Fri, 25 Jan 2019 17:52:09 -0500 Subject: [PATCH 23/23] 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