Android: сворачивание нескольких элементов ListView с анимацией

Как я могу сделать анимацию, сворачивающуюся и скрывающую определенные элементы в ListView?

public class Post {
 public String title;
 public boolean isVisible;
 }

В настоящее время я устанавливаю флаг isVisible постов на false, вызывая адаптер notifyDataSetChanged() и устанавливая каждую видимость View в соответствии с флагом isVisible в getView(int position, View convertView, ViewGroup parent).

Например, если у меня были сообщения:

В С D Е

и я хотел скрыть B и C, как бы я мог оживить D, прокручивая до A и скрывая B и C?

1 ответ

вам не нужен отдельный Animator для каждого элемента, вы можете сделать это с помощью одного ValueAnimator. Код ниже работает для SDK> = 12.

main.xml

<linearlayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:gravity="center_horizontal" android:layout_width="match_parent" android:layout_height="match_parent">

 </linearlayout>

outer.xml

<linearlayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:gravity="center_horizontal" android:layout_width="match_parent" android:layout_height="match_parent">

 <textview android:id="@+id/textAboveList" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="click section headers to collapse / expand children">

 </textview></linearlayout>

header.xml

<linearlayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="wrap_content" android:background="#2F2F2F" android:gravity="center_vertical">

 </linearlayout>

item.xml

<!--?xml version="1.0" encoding="utf-8"?-->
<linearlayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="wrap_content" android:gravity="center_vertical">

 </linearlayout>

Inner.java

package com.example.sectionheaders;

import java.util.ArrayList;
import java.util.TreeMap;

import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.app.ListFragment;
import android.content.Context;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;

public class Inner extends ListFragment {

 private static final String TAG = "Inner";
 private static final int shrinkExpandAnimationDuration = 500;

 @Override
 public void onListItemClick(ListView l, View v, int position, long id) {
 CustomAdapter adap = (CustomAdapter)getListAdapter();
 String text =(String) adap.getItem(position);
 int itemType = adap.getItemViewType(position);
 if (itemType == CustomAdapter.ITEM){
 Log.i(TAG, "you clicked item: " + text);
 } else {
 int vis = adap.getSectionVisibility(position);
 if (vis == CustomAdapter.SHRINKING || vis == CustomAdapter.EXPANDING){
 Log.i(TAG, "animation already running, ignoring click");
 } else {
 if (vis == CustomAdapter.VISIBLE){
 Log.i(TAG, "hiding section " + text);
 adap.setSectionShrinking(position);
 makeItemHeightShrinker(adap, position, shrinkExpandAnimationDuration).start();
 } else {
 if (vis == CustomAdapter.INVISIBLE){
 Log.i(TAG, "showing section " + text);
 adap.setSectionExpanding(position);
 makeItemHeightExpander(adap, position, shrinkExpandAnimationDuration).start();
 }
 }
 }
 }
 }
 ValueAnimator makeItemHeightShrinker(final CustomAdapter adap, final int position, int durationMillis){
 ValueAnimator result = ValueAnimator.ofFloat(0, 1);
 result.setDuration(durationMillis);
 AnimatorUpdateListener shrink = new AnimatorUpdateListener() {
 @Override
 public void onAnimationUpdate(ValueAnimator parameterSpawner){
 ****** lambda = parameterSpawner.getAnimatedFraction();
 ****** relHeight = 1 - lambda;
 // loop through elements to be hidden, and for each of them, set height to "natural height" * (1-lambda)
 Log.i(TAG, "----- shrinking ------- animated fraction: " + lambda);
 adap.setKidsRelHeightUnderSection(position, relHeight);
 if (lambda == 1){
 adap.setSectionInvisible(position);
 }
 }
 };
 result.addUpdateListener(shrink);
 return result;
 };
 ValueAnimator makeItemHeightExpander(final CustomAdapter adap, final int position, int durationMillis){
 ValueAnimator result = ValueAnimator.ofFloat(0, 1);
 result.setDuration(durationMillis);
 AnimatorUpdateListener knirhs = new AnimatorUpdateListener() {
 @Override
 public void onAnimationUpdate(ValueAnimator parameterSpawner){
 ****** lambda = parameterSpawner.getAnimatedFraction();
 // loop through elements to be hidden, and for each of them, set height to "natural height" * lambda
 Log.i(TAG, "----- expanding ------- animated fraction: " + lambda);
 adap.setKidsRelHeightUnderSection(position, lambda);
 if (lambda == 1){
 adap.setSectionVisible(position);
 }
 }
 };
 result.addUpdateListener(knirhs);
 return result;
 };

 public static class CustomAdapter extends BaseAdapter {

 private static final int ITEM = 0;
 private static final int HEADER = 1;

 private static final int VISIBLE = 0;
 private static final int SHRINKING = 1;
 private static final int INVISIBLE = 2;
 private static final int EXPANDING = 3;

 private static final int ITEM_HEIGHT = 85;

 private ArrayList<string> mData = new ArrayList<string>();
 private TreeMap<integer, integer=""> sectionVisibility = new TreeMap<integer, integer="">();
 // sectionVisibility.get(i) = VISIBLE iff ith item is a header of a visible section
 // sectionVisibility.get(i) = SHRINKING iff ith item is a header of a section which is in the process of being shrunken by animation
 // sectionVisibility.get(i) = INVISIBLE iff ith item is a header of an invisible section
 // sectionVisibility.get(i) = EXPANDING iff ith item is a header of a section which is in the process of being expanded by animation
 // !sectionVisibility.containsKey(i) iff ith item is not a section header, but regular item
 private TreeMap<integer, integer=""> parentItem = new TreeMap<integer, integer="">();
 // parentItem(i) = j, iff jth item is the section header above the ith item
 private TreeMap<integer, ******=""> kidsRelHeightUnderSection = new TreeMap<integer, ******="">();

 private LayoutInflater mInflater;

 public CustomAdapter(Context context) {
 mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
 }
 public int addSection(final String sectionHeader, final ArrayList<string> kids){
 int headerIndex = mData.size();
 sectionVisibility.put(headerIndex, VISIBLE);
 kidsRelHeightUnderSection.put(headerIndex, 1.0);
 mData.add(sectionHeader);
 for (int i=0; i</string></integer,></integer,></integer,></integer,></integer,></integer,></string></string>
<p> Outer.java</p> <pre class="prettyprint linenums">package com.example.sectionheaders; import android.app.Fragment; import android.app.FragmentManager; import android.app.FragmentTransaction; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; public class Outer extends Fragment { public Inner inner; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View v = inflater.inflate(R.layout.outer, container, false); FragmentManager fm = getFragmentManager(); FragmentTransaction ft = fm.beginTransaction(); ft.add(R.id.listContainer, inner, "inner").commit(); return v; } } </pre> <p> MainActivity.java</p> <pre class="prettyprint linenums">package com.example.sectionheaders; import java.util.ArrayList; import java.util.Arrays; import android.app.Activity; import android.app.Fragment; import android.app.FragmentManager; import android.app.FragmentTransaction; import android.os.Bundle; import android.util.Log; public class MainActivity extends Activity { Fragment content; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); FragmentManager fm = getFragmentManager(); content = fm.findFragmentById(R.id.contentFragment); if (content == null){ Log.i("Main", "content is null"); Outer outer = new Outer(); outer.inner = new Inner(); FragmentTransaction ft = fm.beginTransaction(); ft.add(R.id.contentFragment, outer, "blah").commit(); content = outer; Inner.CustomAdapter adap = new Inner.CustomAdapter(this); adap.addSection("A", new ArrayList<string>(Arrays.asList(new String[]{"A1", "A2", "A3"}))); adap.addSection("B", new ArrayList<string>(Arrays.asList(new String[]{"B1", "B2", "B3"}))); adap.addSection("C", new ArrayList<string>(Arrays.asList(new String[]{"C1", "C2", "C3"}))); adap.addSection("D", new ArrayList<string>(Arrays.asList(new String[]{"D1", "D2", "D3"}))); adap.addSection("E", new ArrayList<string>(Arrays.asList(new String[]{"E1", "E2", "E3"}))); adap.addSection("F", new ArrayList<string>(Arrays.asList(new String[]{"F1", "F2", "F3"}))); adap.addSection("G", new ArrayList<string>(Arrays.asList(new String[]{"G1", "G2", "G3"}))); adap.addSection("H", new ArrayList<string>(Arrays.asList(new String[]{"H1", "H2", "H3"}))); adap.addSection("I", new ArrayList<string>(Arrays.asList(new String[]{"I1", "I2", "I3"}))); adap.addSection("J", new ArrayList<string>(Arrays.asList(new String[]{"J1", "J2", "J3"}))); adap.addSection("K", new ArrayList<string>(Arrays.asList(new String[]{"K1", "K2", "K3"}))); adap.addSection("L", new ArrayList<string>(Arrays.asList(new String[]{"L1", "L2", "L3"}))); adap.addSection("M", new ArrayList<string>(Arrays.asList(new String[]{"M1", "M2", "M3"}))); outer.inner.setListAdapter(adap); } else { Log.i("Main", "content not null"); } } } </string></string></string></string></string></string></string></string></string></string></string></string></string></pre>

licensed under cc by-sa 3.0 with attribution.