1

I have a ListView that gets data from a JSON on an AWS S3 server, but there's too much data on each item to display by default, there wouldn't be enough items on the screen at once, along with it looking like complete ass.

So I set out to make the items expandable on the user tapping it. I attempted solutions from here, but it's failure to work has just left me with the conclusion the those solutions are meant for one TextView, and not multiple TextViews nestled inside a LinearLayout.

Here's list_item.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:padding="@dimen/activity_horizontal_margin">
    <TextView
        android:id="@+id/name"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:paddingBottom="2dip"
        android:textStyle="bold"
        android:textColor="@color/colorAccent"/>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:id="@+id/expandable">
        <TextView
            android:id="@+id/description"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textColor="#5d5d5d" />
        <TextView
            android:id="@+id/email"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textColor="#5d5d40" />
        <TextView
            android:id="@+id/telephone"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textColor="#5d5d40" />
        <TextView
            android:id="@+id/county"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textColor="#6438"
            android:textStyle="bold"
            android:textSize="20px"/>
    </LinearLayout>

</LinearLayout>

I hope there's a solution to this. The result doesn't have to be animated or beautiful, but that would be appreciated. But really, I want a quick, practical solution that can be scaled to include more information and items, maybe with multiple open at once, if possible.

Thank you in advance.

Willzoy
  • 37
  • 1
  • 7

2 Answers2

2

I had the same scenario in one of my projects. I would set your expandable layout height to 0:

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="0"
    android:orientation="vertical"
    android:id="@+id/expandable">

Once you click on your item, you could measure your "hidden" view by this code:

expandableView = "your_root_view".findViewById(R.id.expandable);
expandableView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
int newHeight = expandableView.getMeasuredHeight();

...and apply a slide animation this way:

ValueAnimator slideAnimator = ValueAnimator.ofInt(0, newHeight);
slideAnimator.setInterpolator(new DecelerateInterpolator());
slideAnimator.setDuration(300);
slideAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            expandableView.getLayoutParams().height = (int) animation.getAnimatedValue();
            expandableView.requestLayout();
        }
    });
slideAnimator.start();

If you want the reverse animation just use:

ValueAnimator.ofInt(newHeight, 0);
Roberto Martucci
  • 1,237
  • 1
  • 13
  • 21
  • on the line `int newHeight = view.getMeasuredHeight();`, what is `view` referring to, exactly? – Willzoy Feb 01 '18 at 19:04
  • 1
    You're right, just a typo. I edited the answer. It is `expandableView.getMeasuredHeight()` – Roberto Martucci Feb 01 '18 at 19:08
  • So I put your code into an `OnItemClickListener` below my adapter, and when I tap on an item, the app freezes and dumps me onto the launch activity. Debugger cites `java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.LinearLayout.measure(int, int)' on a null object reference` – Willzoy Feb 01 '18 at 19:51
  • 1
    Well, of course you need to bind the view, calling `findViewById` on your root view. I don't have your code, so it is something you need to think about by yourself. I edited the answer to let you understand better. – Roberto Martucci Feb 01 '18 at 20:00
  • That's great, thanks! But one last question before I stop pestering you: Why is it that when I tap on any item on the screen, only the topmost visible one will expand? – Willzoy Feb 01 '18 at 20:19
  • 1
    Probably you're calling findViewById always on the same rootView instead of each itemView one. Try to call it on the view that `onItemClick(AdapterView> parent, View view, int position, long id)` pass you as parameter – Roberto Martucci Feb 01 '18 at 21:56
0

An easy way you can do is to add android:animateLayoutChanges="true" and update the visibility of the views you want to show upon click.

<LinearLayout 
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:animateLayoutChanges="true">

Another way is to use TransitionManager this is more flexible because you can customize your animation. You just need to call TransitionManager.beginDelayedTransition before updating your views.

root.setOnClickListener {
    TransitionManager.beginDelayedTransition(root, AutoTransition())
    root.findViewById(R.id.gone1).visibility = View.VISIBLE
    root.findViewById(R.id.gone2).visibility = View.VISIBLE
    root.findViewById(R.id.gone3).visibility = View.VISIBLE
}

Hope it can help you, also I suggest on switching to RecyclerView instead of using ListView.

GDA
  • 334
  • 2
  • 7