我如何进行动画折叠和隐藏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?
答案 0 :(得分:0)
对于每个项目,您不需要单独的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">
<FrameLayout
android:id="@+id/contentFragment"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</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" />
<FrameLayout
android:id="@+id/listContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</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" >
<TextView
android:id="@+id/headerText"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="8dp"
android:text=""
android:textAppearance="?android:attr/textAppearanceLarge"
android:textColor="#FFF"
android:textStyle="bold"
android:visibility="visible" />
</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" >
<TextView
android:id="@+id/itemText"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#FFF"
android:gravity="center_vertical"
android:padding="5dp"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textColor="#FF000000" />
</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){
double lambda = parameterSpawner.getAnimatedFraction();
double 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){
double 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, Double> kidsRelHeightUnderSection = new TreeMap<Integer, Double>();
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<kids.size(); i++){
int kidIndex = mData.size();
String kid = kids.get(i);
mData.add(kid);
parentItem.put(kidIndex, headerIndex);
}
notifyDataSetChanged();
return headerIndex;
}
public void setKidsRelHeightUnderSection(final int sectionIndex, double relativeHeight){
kidsRelHeightUnderSection.put(sectionIndex, relativeHeight);
notifyDataSetChanged();
}
public void setSectionVisible(int sectionIndex){
if (!sectionVisibility.containsKey(sectionIndex)){
Log.wtf(TAG, "bad programmer");
return;
}
sectionVisibility.put(sectionIndex, VISIBLE);
notifyDataSetChanged();
}
public void setSectionInvisible(int sectionIndex){
if (!sectionVisibility.containsKey(sectionIndex)){
Log.wtf(TAG, "bad programmer");
return;
}
sectionVisibility.put(sectionIndex, INVISIBLE);
notifyDataSetChanged();
}
public void setSectionShrinking(int sectionIndex){
if (!sectionVisibility.containsKey(sectionIndex)){
Log.wtf(TAG, "bad programmer");
return;
}
sectionVisibility.put(sectionIndex, SHRINKING);
}
public void setSectionExpanding(int sectionIndex){
if (!sectionVisibility.containsKey(sectionIndex)){
Log.wtf(TAG, "bad programmer");
return;
}
sectionVisibility.put(sectionIndex, EXPANDING);
}
public int getSectionVisibility(final int sectionIndex){
return sectionVisibility.get(sectionIndex);
}
@Override
public int getItemViewType(int position) {
return sectionVisibility.containsKey(position) ? HEADER : ITEM;
}
@Override
public int getViewTypeCount() {
return 2;
}
@Override
public int getCount() {
return mData.size();
}
@Override
public String getItem(int position) {
return mData.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
private void adjustTextView(TextView tv, int state, int height, int position){
if (state == INVISIBLE){
tv.setVisibility(View.GONE);
return;
}
tv.setVisibility(View.VISIBLE);
LayoutParams lp = tv.getLayoutParams();
if (lp == null){
lp = new LayoutParams(LayoutParams.MATCH_PARENT, height);
} else {
lp.height = height;
}
tv.setLayoutParams(lp);
}
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
int rowType = getItemViewType(position);
if (convertView == null) {
holder = new ViewHolder();
switch (rowType) {
case ITEM:
convertView = mInflater.inflate(R.layout.item, parent, false);
holder.textView = (TextView) convertView.findViewById(R.id.itemText);
break;
case HEADER:
convertView = mInflater.inflate(R.layout.header, parent, false);
holder.textView = (TextView) convertView.findViewById(R.id.headerText);
break;
}
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.textView.setText(mData.get(position));
if (rowType == ITEM){
Integer myParentItem = parentItem.get(position);
int itemVisibility = sectionVisibility.get(myParentItem);
//View parentView = (View)holder.textView.getParent();
int newHeight = LayoutParams.WRAP_CONTENT;
if (itemVisibility == SHRINKING || itemVisibility == EXPANDING){
newHeight = (int)Math.round(kidsRelHeightUnderSection.get(myParentItem) * ITEM_HEIGHT);
}
adjustTextView(holder.textView, itemVisibility, newHeight, position);
}
return convertView;
}
public static class ViewHolder {
public TextView textView;
}
}
}
Outer.java
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;
}
}
MainActivity.java
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");
}
}
}