0

Whats the best way to animate a button in android based on scroll events?

I have a button which is located in the bottom right corner of the view and I'd like to animate the button to move below the bottom viewport when the user is scrolling down and up, if the user scrolls up.

My Layout:

I used the ObservableScrollView from this example (Synchronise ScrollView scroll positions - android)

<RelativeLayout ...>
    <ObservableScrollView ...> 
        <LinearLayout ...>
            <!-- <Items> -->
        </LinearLayout>
    </ObservableScrollView>
    <Button />
</RelativeLayout>

edit:

attached some scala code

observableScrollView.setScrollViewListener(new ScrollViewListener {
  override def onScrollChanged(scrollView: ObservableScrollView, x: Int, y: Int, oldx: Int, oldy: Int): Unit = {

    val scrollBottom = linearLayout.getHeight - observableScrollView.getHeight - 20

    if (y >= scrollBottom) { // reached bottom
      composeButton.stateChange(STATE_SHOW)
    } else if (y > 0 && oldy > 0 && y > oldy) { // scroll up
      composeButton.stateChange(STATE_HIDE)
    } else if (y > 0 && oldy > 0 && y < oldy) { // scroll down
      composeButton.stateChange(STATE_SHOW)
    }
  }
})

=====

val animationDuration: Int = 1000
lazy val yStartPosition = getY // initialized on first access
var currentState: ComposeButtonState = STATE_SHOW
val animationQueue: AnimatorSet = new AnimatorSet()


def animate(from:Float, to:Float) = {
  val anim = ObjectAnimator.ofFloat(this, "y", from, to)
  anim.setDuration(animationDuration)
  anim.setInterpolator(new OvershootInterpolator())
  animationQueue.play(anim)
  animationQueue.start()
}

def stateChange(state: ComposeButtonState) = {
  if (state != currentState) {
    currentState = state
    state match {
      case STATE_SHOW => animate(yStartPosition + yTranslateInitialValue, yStartPosition)
      case STATE_HIDE => animate(yStartPosition, yStartPosition + yTranslateInitialValue)
    }
  }
}
Community
  • 1
  • 1
sonix
  • 243
  • 2
  • 17

1 Answers1

1

Use an ObjectAnimator with

@Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
        super.onScrollChanged(l, t, oldl, oldt);
       //do something cool
    }

Object Animator example:

ObjectAnimator myAnimation = ObjectAnimator.ofFloat(yourButton, "translationY",
                yourButton.getY(), screenHeight);
erik
  • 4,946
  • 13
  • 70
  • 120
  • I added the button in the layout, so I want its Y-position when it is added. Is there any event fired on a button like "onCreated", "onAdded" or sth. else? – sonix Jul 23 '14 at 13:21
  • i assume you could use: .addOnGlobalLayoutListener(new OnGlobalLayoutListener() { @Override public void onGlobalLayout() { } }); – erik Jul 23 '14 at 13:23
  • but you can also get the Y position at time of animation.. i'll add an example to my answer – erik Jul 23 '14 at 13:24
  • Problem ist, that the animations are overlapping. If you scroll up and down within the duration, the Y-position differs and will produce different y-offsets – sonix Jul 23 '14 at 13:42
  • I am not sure what you are saying.. please post your code.. also take note of this: public void setAutoCancel (boolean cancel) Added in API level 18 autoCancel controls whether an ObjectAnimator will be canceled automatically when any other ObjectAnimator with the same target and properties is started. – erik Jul 23 '14 at 14:00
  • I edited the question: animationQueue.play(anim) and animationQueue.start() will interrupt any already playing animation on the "composeButton". This doesn't look very snappy in the ui. – sonix Jul 23 '14 at 14:26
  • where are you setting yTranslateInitialValue & yStartPosition? don't you want to set them at the time you start the animation? – erik Jul 23 '14 at 14:33
  • yTranslateInitialValue is constant and yStartPosition will be initalized with the y-position on first access to ensure it is set with the initial value of the xml layout – sonix Jul 23 '14 at 15:55