javaandroidtextviewandroid-linearlayout

Android Scrolling/Fading Text Programatically Appended To


I'm building an old-school type android game, and one of the things I'd like to have is a "combat results text window" where I can add text as actions happen, so the player knows what's going on.

I currently have used a textview and a valueAnimator to fade the text out:

public void updateCommentary(String updatedText){

    runOnUiThread(new Runnable() {

      @Override
      public void run() {
          ValueAnimator valueAnimator = ValueAnimator.ofFloat(1f, 0f);
          valueAnimator.setDuration(5000);
          valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
              @Override
              public void onAnimationUpdate(ValueAnimator animation) {
                  TextView tv = (TextView) findViewById(R.id.txtRunningCommentary);
                  tv.setText(updatedText);
                  float alpha = (float) animation.getAnimatedValue();
                  tv.setAlpha(alpha);
              }
          });
          valueAnimator.start();
      }
    });
}

This works to the point where any updates will drop in and fade out, but if called a quickly in succession, the following text over-write what's there already.

What I'd like to do, is instead have say, 5 lines of text, and let me keep adding new updates, which push the previous updates up, and as they get further up they fade out. If there are no updates for long enough, have the text fade out on it's own. Finally, in a perfect world, the widget would not have a fixed height, but understand how many lines can fit in it, and have the desired functionality based on that user's device/screen layout.

Currently Working with Single Textview

I have thought of doing this with a number of textviews, and at the start of the function moving the contents of textview2 into textview1, then moving trextview3 into textview2 and so on, and finally adding the newest update into textview5 - but this feels limited on a few points:

I have also considered adding a scrollable vertical linearLayout and appending new textviews to it... and somehow fading them out and deleting them... but again, starting to feel like it's getting overly complicated for the expected functionality?

Is there a android class that I could use in some way to achieve this, or is my horrid way about as good as it's going to get?


Solution

  • If you only need to fade out the text, no additional transformation, or scaling at all, I have a small trick for you:

    Create a gradient background drawable that smoothly fades from white to transparent:

    bgr_shadow_white_down.xml

    <?xml version="1.0" encoding="utf-8"?>
    <shape xmlns:android="http://schemas.android.com/apk/res/android"
        android:shape="rectangle">
    
        <gradient
            android:angle="-90"
            android:endColor="@android:color/transparent"
            android:startColor="@color/white" />
    </shape>
    

    You can create another drawable that fading bottom up:

    bgr_shadow_white_up.xml

    <?xml version="1.0" encoding="utf-8"?>
    <shape xmlns:android="http://schemas.android.com/apk/res/android"
        android:shape="rectangle">
    
        <gradient
            android:angle="90"
            android:endColor="@android:color/transparent"
            android:startColor="@color/white" />
    </shape>
    

    Then you can have a layout like this:

    <?xml version="1.0" encoding="utf-8"?>
    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="100dp">
    
        <TextView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_marginHorizontal="10dp"
            tools:text="@tools:sample/lorem/random" />
    
        <View
            android:layout_width="match_parent"
            android:layout_height="32dp"
            android:background="@drawable/bgr_shadow_white_down" />
    
        <View
            android:layout_width="match_parent"
            android:layout_height="32dp"
            android:layout_gravity="bottom"
            android:background="@drawable/bgr_shadow_white_up" />
    </FrameLayout>
    

    Visual:

    Visualize fade overlay

    You will have a TextView with a fade effect on top and bottom. Now in your use case, you can: