1

I want to animate the keyboard when a new line is added or removed just like how telegram does. I am able to add the animation like this:

private void doAnimation(int linesCount, String s){
        Toast.makeText(this, "" + linesCount, Toast.LENGTH_SHORT).show();
        if (linesCount == 1){
            binding.message.getLayoutParams().height = defEditTextHeight;
            return;
        }
        if (linesCount < binding.message.getLineCount()) {
            ValueAnimator anim = ValueAnimator.ofInt(binding.message.getHeight(), binding.message.getHeight() + 60)
                    .setDuration(250);
            anim.addUpdateListener(animation -> {
                binding.message.getLayoutParams().height = (int) animation.getAnimatedValue();
                binding.message.requestLayout();
            });
            anim.start();
        }else if( linesCount > binding.message.getLineCount()){
            ValueAnimator anim = ValueAnimator.ofInt(binding.message.getHeight(), binding.message.getHeight() - 60)
                    .setDuration(250);
            anim.addUpdateListener(animation -> {
                binding.message.getLayoutParams().height = (int) animation.getAnimatedValue();
                binding.message.requestLayout();
            });
            anim.start();
        }
    }

But, as you can see for the animation I am adding a random value like 60. But, this is not reliable for all the devices.

So, how can I get the height of each line so that I can add it and get a good animation?

Thanks in advance

Sambhav Khandelwal
  • 3,585
  • 2
  • 7
  • 38
  • Capture the height of the text when each line is added. Then, when another line is added or removed, the difference between the current height and the last height is the amount to grow or shrink. Does it need to be any more complicated than that? – Cheticamp Mar 20 '22 at 13:22
  • @Cheticamp let me try that. Actually the `getHeight()` method returns 0 and `getLayoutParams().height` gives -2. I had tried what you had said. But, it does not work – Sambhav Khandelwal Mar 20 '22 at 13:34
  • If `getHeight()` returns zero, you will have to wait for layout to get the measurement. – Cheticamp Mar 20 '22 at 13:49
  • can you provide the code? – Sambhav Khandelwal Mar 20 '22 at 13:49
  • To wait for layout to complete, take a look at [View.OnLayoutChangeListener](https://developer.android.com/reference/android/view/View.OnLayoutChangeListener) or [ViewTreeObserver.OnGlobalLayoutListener](https://developer.android.com/reference/android/view/ViewTreeObserver.OnGlobalLayoutListener). There are sample of usage online. – Cheticamp Mar 20 '22 at 13:54
  • Thanks. It would be great if you could post it as an answer. I will test it out – Sambhav Khandelwal Mar 20 '22 at 13:55

1 Answers1

1

The height of each line of an EditText is given by a StaticLayout that is created by the EditText.

// Get vertical padding of the EditText
int padding = binding.message.getPaddingTop() + binding.message.getPaddingBottom();

// Get the total height of the EditText
int totalHeight = binding.message.getLayout().getHeight() + padding;
// or
int totalHeight = binding.message.getHeight();

// Get the height that line i contributes to the EditText. 
int height = binding.message.getLayout().getLineBottom(i) - binding.message.getLayout().getLineTop(i);

So, your animation definitions would look like this:

int i = linesCount - 1;
int height = binding.message.getLayout().getLineBottom(i) - binding.message.getLayout().getLineTop(i);
ValueAnimator anim = ValueAnimator.ofInt(binding.message.getHeight(), binding.message.getHeight() + height)
                .setDuration(250);

If you need to wait for the layout, you can use the following:

binding.message.addOnLayoutChangeListener((v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
    // code here 
};
Cheticamp
  • 61,413
  • 10
  • 78
  • 131