36

Mam numer ListView. Początkowo urządzenie ListView zawiera pewne dane. Gdy użytkownik kliknie element, inny układ zostanie dynamicznie dodany do tego elementu, aby zwiększyć jego wysokość.Rozwiń pozycję ListView z animacją

W tej chwili, gdy wysokość przedmiotu jest większa, natychmiast pokazuje zmodyfikowany przedmiot. Jednak to, czego chcę, to animacja, aby stopniowo zwiększać wysokość przedmiotu.

Odpowiedz

33

Wydaje mi się, że szukałem tego samego, co zostało zadane, szukałem sposobu, aby ożywić rozwinięcie elementu listview jako nowego zawartość jest wyświetlana (właśnie zmieniałem widoczność niektórych widoków z GONE na VISIBLE). I użył odpowiedź przez mirroredAbstraction mi pomóc zastosować animację translate (nie chcę się obracać animację):

<translate xmlns:android="http://schemas.android.com/apk/res/android" 
android:interpolator="@android:anim/linear_interpolator" 
android:fromYDelta="0" 
android:toYDelta="-100%p" 
android:duration="500" 
/> 

do każdego z widoków. Stwarza to przyjemny efekt, ale patrząc uważnie, element listview nagle rozszerzył się do całego rozmiaru, który byłby potrzebny, a następnie animacja upuściła widoki na miejsce. Ale to, czego chciałem, to efekt elementu listview, który rośnie, gdy widoki stają się widoczne.

znalazłem dokładnie to, czego szukałem tutaj: expanding-listview-items

Bloger ma link do jego próbki github, tutaj: ExpandAnimationExample

Jeśli znajdziesz te strony nie ma, prosimy o poinformowanie mnie i ja udostępni moją kopię.

włożył ujemną marżę na zawartość przyjść do widoczności, a także ustawienie widoczności GONE:

android:layout_marginBottom="-50dip" 

i napisał animację manipulując dolnego marginesu:

public class ExpandAnimation extends Animation { 
... 
    @Override 
    protected void applyTransformation(float interpolatedTime, Transformation t) { 
     super.applyTransformation(interpolatedTime, t); 

     if (interpolatedTime < 1.0f) { 

      // Calculating the new bottom margin, and setting it 
      mViewLayoutParams.bottomMargin = mMarginStart 
        + (int) ((mMarginEnd - mMarginStart) * interpolatedTime); 

      // Invalidating the layout, making us seeing the changes we made 
      mAnimatedView.requestLayout(); 
     } 
     ... 
    } 
} 

i wygląda bardzo dobrze. Znalazłem jego odpowiedź na to pytanie SO (możliwy duplikat?):

Adding animation to a ListView in order to expand/collapse content

Także, proszę dać mi znać, jeśli znasz inny sposób, aby zrobić to samo.

+1

W takim przypadku wysokość przedmiotu ListView jest znana z góry. Ale w moim przypadku jest dynamiczny. Mam na myśli, że wysokość rozwiniętego układu będzie znana w czasie wykonywania. – Manjunath

+1

Tak, widzę ... Myślę, że być może będę potrzebował mieć taki wpływ na dynamicznie dodawane/tworzone treści. Ja też wciąż patrzę. Chciałbym odpowiedzieć na twoje pytanie, aby więcej osób je widziało, ale nie byłeś zbyt szczegółowy (tj. Pominąłeś część dynamiczną!), A przynajmniej powinieneś przeformułować mylące stwierdzenie: "A więc, co teraz? Chcę: gdy wysokość przedmiotu jest większa, nagle pokazuje zmodyfikowany przedmiot, ale muszę animować, gdy zwiększa on wysokość przedmiotu. " – David

6

Trzeba będzie wdrożyć animacji Adapter was ListView aby osiągnąć to, co chcesz,

pierwsze utworzyć podstawowy animation.xml pliku, utwórz folder o nazwie anim w OZE folderze, a następnie umieścić w nim plik animation.xml .

Dla np. I stworzyli animację przykładowy nazwie rotate_animation.xml

<?xml version="1.0" encoding="UTF-8"?> 
<rotate 
    xmlns:android="http://schemas.android.com/apk/res/android" 
    android:fromDegrees="0" 
    android:toDegrees="360" 
    android:pivotX="50%" 
    android:pivotY="50%" 
    android:duration="400" /> 

Następnie należy utworzyć instancję AnimationObject jak ten

private Animation animation; 

Następnie w metodzie getView swojej implementacji adaptera zrobić coś takiego

public View getView(int position, View convertView, ViewGroup parent) { 
     View v = convertView; 
     ViewHolder viewHolder; 
     if (convertView == null) { 
      LayoutInflater li = (LayoutInflater) mContext 
        .getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
      v = li.inflate(R.layout.my_layout, null); 
      viewHolder = new ViewHolder(v); 
      v.setTag(viewHolder); 

     } else { 
      viewHolder = (ViewHolder) v.getTag(); 
     } 

     viewHolder.mAppName.setText("SomeText"); 
     viewHolder.mAppImage.setImageDrawable(R.drawable.someImage); 
     animation = AnimationUtils.loadAnimation(mContext, R.anim.my_animation); 
     v.startAnimation(animation); 
     return v; 
    } 
15

Zaimplementowałem prosty kod, który działa we wszystkich wersjach SDK Androida.

Zobacz poniżej jego działanie i kod. Kod

Github: https://github.com/LeonardoCardoso/Animated-Expanding-ListView

uzyskać informacje na mojej stronie internetowej: http://android.leocardz.com/animated-expanding-listview/

normalaccordion

Zasadniczo trzeba utworzyć niestandardową TranslateAnimation i niestandardową listę Adapter, a podczas jego animacji, ty należy zaktualizować bieżącą wysokość elementu listview i powiadomić adapter o tej zmianie.

Przejdźmy do kodu.

  1. układ Wykaz egzemplarzy

    <?xml version="1.0" encoding="utf-8"?> 
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
         android:id="@+id/text_wrap" 
         android:layout_width="match_parent" 
         android:layout_height="wrap_content" 
         android:orientation="horizontal" 
         android:paddingBottom="@dimen/activity_vertical_margin" 
         android:paddingLeft="@dimen/activity_horizontal_margin" 
         android:paddingRight="@dimen/activity_horizontal_margin" 
         android:paddingTop="@dimen/activity_vertical_margin" > 
    
         <TextView 
          android:id="@+id/text" 
          android:layout_width="match_parent" 
          android:layout_height="wrap_content" 
          android:textSize="18sp" > 
         </TextView> 
    
    </LinearLayout> 
    
  2. Układ aktywny

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
          xmlns:tools="http://schemas.android.com/tools" 
          android:layout_width="match_parent" 
          android:layout_height="match_parent" 
          tools:context=".MainActivity" > 
    
          <ListView 
           android:id="@+id/list" 
           android:layout_width="match_parent" 
           android:layout_height="wrap_content" 
           android:divider="@android:color/black" 
           android:dividerHeight="3dp" > 
          </ListView> 
    
         </RelativeLayout> 
    
  3. klasa Wykaz egzemplarzy

    public class ListItem { 
    
    private String text; 
    private int collapsedHeight, currentHeight, expandedHeight; 
    private boolean isOpen; 
    private ListViewHolder holder; 
    private int drawable; 
    
    public ListItem(String text, int collapsedHeight, int currentHeight, 
         int expandedHeight) { 
        super(); 
        this.text = text; 
        this.collapsedHeight = collapsedHeight; 
        this.currentHeight = currentHeight; 
        this.expandedHeight = expandedHeight; 
        this.isOpen = false; 
        this.drawable = R.drawable.down; 
    } 
    
    public String getText() { 
        return text; 
    } 
    
    public void setText(String text) { 
        this.text = text; 
    } 
    
    public int getCollapsedHeight() { 
        return collapsedHeight; 
    } 
    
    public void setCollapsedHeight(int collapsedHeight) { 
        this.collapsedHeight = collapsedHeight; 
    } 
    
    public int getCurrentHeight() { 
        return currentHeight; 
    } 
    
    public void setCurrentHeight(int currentHeight) { 
        this.currentHeight = currentHeight; 
    } 
    
    public int getExpandedHeight() { 
        return expandedHeight; 
    } 
    
    public void setExpandedHeight(int expandedHeight) { 
        this.expandedHeight = expandedHeight; 
    } 
    
    public boolean isOpen() { 
        return isOpen; 
    } 
    
    public void setOpen(boolean isOpen) { 
        this.isOpen = isOpen; 
    } 
    
    public ListViewHolder getHolder() { 
        return holder; 
    } 
    
    public void setHolder(ListViewHolder holder) { 
        this.holder = holder; 
    } 
    
    public int getDrawable() { 
        return drawable; 
    } 
    
    public void setDrawable(int drawable) { 
        this.drawable = drawable; 
    } 
    } 
    
  4. klasa Zobacz Holder

    public class ListViewHolder { 
    private LinearLayout textViewWrap; 
    private TextView textView; 
    
    public ListViewHolder(LinearLayout textViewWrap, TextView textView) { 
        super(); 
        this.textViewWrap = textViewWrap; 
        this.textView = textView; 
    } 
    
    public TextView getTextView() { 
         return textView; 
    } 
    
    public void setTextView(TextView textView) { 
        this.textView = textView; 
    } 
    
    public LinearLayout getTextViewWrap() { 
        return textViewWrap; 
    } 
    
    public void setTextViewWrap(LinearLayout textViewWrap) { 
        this.textViewWrap = textViewWrap; 
    } 
    } 
    
  5. Animacja niestandardowa klasa klasa

    public class ResizeAnimation extends Animation { 
        private View mView; 
        private float mToHeight; 
        private float mFromHeight; 
    
        private float mToWidth; 
        private float mFromWidth; 
    
        private ListAdapter mListAdapter; 
        private ListItem mListItem; 
    
        public ResizeAnimation(ListAdapter listAdapter, ListItem listItem, 
          float fromWidth, float fromHeight, float toWidth, float toHeight) { 
         mToHeight = toHeight; 
         mToWidth = toWidth; 
         mFromHeight = fromHeight; 
         mFromWidth = fromWidth; 
         mView = listItem.getHolder().getTextViewWrap(); 
         mListAdapter = listAdapter; 
         mListItem = listItem; 
         setDuration(200); 
        } 
    
        @Override 
        protected void applyTransformation(float interpolatedTime, Transformation t) { 
         float height = (mToHeight - mFromHeight) * interpolatedTime 
           + mFromHeight; 
         float width = (mToWidth - mFromWidth) * interpolatedTime + mFromWidth; 
         LayoutParams p = (LayoutParams) mView.getLayoutParams(); 
         p.height = (int) height; 
         p.width = (int) width; 
         mListItem.setCurrentHeight(p.height); 
         mListAdapter.notifyDataSetChanged(); 
        } 
        } 
    
  6. klienta Adapter Lista

    public class ListAdapter extends ArrayAdapter<ListItem> { 
    private ArrayList<ListItem> listItems; 
    private Context context; 
    
    public ListAdapter(Context context, int textViewResourceId, 
        ArrayList<ListItem> listItems) { 
    super(context, textViewResourceId, listItems); 
    this.listItems = listItems; 
    this.context = context; 
    } 
    
    @Override 
    @SuppressWarnings("deprecation") 
    public View getView(int position, View convertView, ViewGroup parent) { 
    ListViewHolder holder = null; 
    ListItem listItem = listItems.get(position); 
    
    if (convertView == null) { 
        LayoutInflater vi = (LayoutInflater) context 
          .getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
        convertView = vi.inflate(R.layout.list_item, null); 
    
        LinearLayout textViewWrap = (LinearLayout) convertView 
          .findViewById(R.id.text_wrap); 
        TextView text = (TextView) convertView.findViewById(R.id.text); 
    
        holder = new ListViewHolder(textViewWrap, text); 
    } else 
        holder = (ListViewHolder) convertView.getTag(); 
    
    holder.getTextView().setText(listItem.getText()); 
    
    LayoutParams layoutParams = new LayoutParams(LayoutParams.FILL_PARENT, 
         listItem.getCurrentHeight()); 
    holder.getTextViewWrap().setLayoutParams(layoutParams); 
    
    holder.getTextView().setCompoundDrawablesWithIntrinsicBounds(
         listItem.getDrawable(), 0, 0, 0); 
    
    convertView.setTag(holder); 
    
    listItem.setHolder(holder); 
    
    return convertView; 
    } 
    
    } 
    
  7. Main Activity

    public class MainActivity extends Activity { 
    
    private ListView listView; 
    private ArrayList<ListItem> listItems; 
    private ListAdapter adapter; 
    
    private final int COLLAPSED_HEIGHT_1 = 150, COLLAPSED_HEIGHT_2 = 200, 
        COLLAPSED_HEIGHT_3 = 250; 
    
    private final int EXPANDED_HEIGHT_1 = 250, EXPANDED_HEIGHT_2 = 300, 
        EXPANDED_HEIGHT_3 = 350, EXPANDED_HEIGHT_4 = 400; 
    
    private boolean accordion = true; 
    
    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_main); 
    
    listView = (ListView) findViewById(R.id.list); 
    
    listItems = new ArrayList<ListItem>(); 
    mockItems(); 
    
    adapter = new ListAdapter(this, R.layout.list_item, listItems); 
    
    listView.setAdapter(adapter); 
    
    listView.setOnItemClickListener(new OnItemClickListener() { 
    
        @Override 
        public void onItemClick(AdapterView<?> parent, View view, 
          int position, long id) { 
         toggle(view, position); 
        } 
    }); 
    } 
    
    private void toggle(View view, final int position) { 
    ListItem listItem = listItems.get(position); 
    listItem.getHolder().setTextViewWrap((LinearLayout) view); 
    
    int fromHeight = 0; 
    int toHeight = 0; 
    
    if (listItem.isOpen()) { 
        fromHeight = listItem.getExpandedHeight(); 
        toHeight = listItem.getCollapsedHeight(); 
    } else { 
        fromHeight = listItem.getCollapsedHeight(); 
        toHeight = listItem.getExpandedHeight(); 
    
        // This closes all item before the selected one opens 
        if (accordion) { 
         closeAll(); 
        } 
    } 
    
    toggleAnimation(listItem, position, fromHeight, toHeight, true); 
    } 
    
    private void closeAll() { 
    int i = 0; 
    for (ListItem listItem : listItems) { 
        if (listItem.isOpen()) { 
         toggleAnimation(listItem, i, listItem.getExpandedHeight(), 
           listItem.getCollapsedHeight(), false); 
        } 
        i++; 
    } 
    } 
    
    private void toggleAnimation(final ListItem listItem, final int position, 
        final int fromHeight, final int toHeight, final boolean goToItem) { 
    
    ResizeAnimation resizeAnimation = new ResizeAnimation(adapter, 
         listItem, 0, fromHeight, 0, toHeight); 
    resizeAnimation.setAnimationListener(new AnimationListener() { 
    
        @Override 
        public void onAnimationStart(Animation animation) { 
        } 
    
        @Override 
        public void onAnimationRepeat(Animation animation) { 
        } 
    
        @Override 
        public void onAnimationEnd(Animation animation) { 
         listItem.setOpen(!listItem.isOpen()); 
         listItem.setDrawable(listItem.isOpen() ? R.drawable.up 
           : R.drawable.down); 
         listItem.setCurrentHeight(toHeight); 
         adapter.notifyDataSetChanged(); 
    
         if (goToItem) 
          goToItem(position); 
        } 
    }); 
    
    listItem.getHolder().getTextViewWrap().startAnimation(resizeAnimation); 
    } 
    
    private void goToItem(final int position) { 
    listView.post(new Runnable() { 
        @Override 
        public void run() { 
         try { 
          listView.smoothScrollToPosition(position); 
         } catch (Exception e) { 
          listView.setSelection(position); 
         } 
        } 
    }); 
    } 
    
    private void mockItems() { 
    listItems 
         .add(new ListItem(
           "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", 
           COLLAPSED_HEIGHT_1, COLLAPSED_HEIGHT_1, 
           EXPANDED_HEIGHT_1)); 
    
    listItems 
         .add(new ListItem(
           "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.", 
           COLLAPSED_HEIGHT_2, COLLAPSED_HEIGHT_2, 
           EXPANDED_HEIGHT_2)); 
    
    listItems 
         .add(new ListItem(
           "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.", 
           COLLAPSED_HEIGHT_3, COLLAPSED_HEIGHT_3, 
           EXPANDED_HEIGHT_3)); 
    
    listItems 
         .add(new ListItem(
           "Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo.", 
           COLLAPSED_HEIGHT_2, COLLAPSED_HEIGHT_2, 
           EXPANDED_HEIGHT_4)); 
    
    listItems 
         .add(new ListItem(
           "At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga.", 
           COLLAPSED_HEIGHT_1, COLLAPSED_HEIGHT_1, 
           EXPANDED_HEIGHT_4)); 
    
    listItems 
         .add(new ListItem(
           "Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus.", 
           COLLAPSED_HEIGHT_2, COLLAPSED_HEIGHT_2, 
           EXPANDED_HEIGHT_4)); 
    
    listItems 
         .add(new ListItem(
           "Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae.", 
           COLLAPSED_HEIGHT_3, COLLAPSED_HEIGHT_3, 
           EXPANDED_HEIGHT_3)); 
    
    listItems 
         .add(new ListItem(
           "Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat.", 
           COLLAPSED_HEIGHT_1, COLLAPSED_HEIGHT_1, 
           EXPANDED_HEIGHT_4)); 
    
        } 
    
    } 
    
+1

Jak dobrze działa ten kod? Widząc, jak to się często zdarza, przetwarzanie złożonych widoków wydaje się dość ciężkie ... – Pkmmte

+0

Rzeczywiście. Ale AFAIK bez częstego powiadamiania listview traci się, jeśli przewiniesz go podczas animowania. –

7

Korzystanie wartości animator rozwiązanie wygląda ładnie:

ValueAnimator animator = ValueAnimator.ofInt(100, 300); 
animator.setDuration(1000); 
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 
    @Override 
    public void onAnimationUpdate(ValueAnimator animation) { 
    listViewItem.getLayoutParams().height = (Integer) animation.getAnimatedValue(); 
    listViewItem.requestLayout(); 
    } 
}); 
animator.start(); 

Wystarczy przeczytać android przewodnik programisty, warto przeczytać: http://developer.android.com/guide/topics/graphics/prop-animation.html

Należy jednak pamiętać, że requestLayout() przetwarzanie jest ciężki. Ponieważ jedno wywołanie requestLayout() powoduje, że każdy element znajdujący się w pobliżu, który jest wizualnie zmieniony, przelicz ponownie jego układ. To może być lepiej użyć ujemny margines dolny (aby ukryć jakąś część swojej elementu pod innym) i korzystać z następujących czynności, aby to pokazać:

listViewItem.setTranslationY((Integer) animation.getAnimatedValue()); 

Oczywiście, można animować tylko dolny margines, jak zaproponowano w inny odpowiedź na to pytanie.

0

Mój przypadek użycia ma na celu wyświetlenie więcej lub mniej tekstu. Aby przełączyć stan elementu listview z 2-6 maks. Linii na przykład, można to zrobić. A także jest animowany. Animacja nie wygląda dokładnie gładko, ale ...

      if(!textDescriptionLenghtToggle) { // simple boolean toggle 
           ObjectAnimator animation = ObjectAnimator.ofInt(
             textViewContainingDescription, 
             "maxLines", 
             6); 
           animation.setDuration(300); 
           animation.start(); 
          } else { 
           ObjectAnimator animation = ObjectAnimator.ofInt(
             textViewContainingDescription, 
             "maxLines", 
             2); 
           animation.setDuration(300); 
           animation.start(); 
          }