android 动态效果学习之旅
一.Android官网上training的这个实例项目 com.example.android.animationsdemo.MainActivity
里面有5种4.0以上的实例效果
1.Simple Crossfade
这是一个文字从无到有逐渐显现的效果,没什么说的,就是一个函数
[java] view plain copy print ?- privatevoid showContentOrLoadingIndicator(boolean contentLoaded) {
- // Decide which view to hide and which to show.
- final View showView = contentLoaded ? mContentView : mLoadingView;
- final View hideView = contentLoaded ? mLoadingView : mContentView;
- // Set the "show" view to 0% opacity but visible, so that it is visible
- // (but fully transparent) during the animation.
- showView.setAlpha(0f);
- showView.setVisibility(View.VISIBLE);
- // Animate the "show" view to 100% opacity, and clear any animation listener set on
- // the view. Remember that listeners are not limited to the specific animation
- // describes in the chained method calls. Listeners are set on the
- // ViewPropertyAnimator object for the view, which persists across several
- // animations.
- showView.animate()
- .alpha(1f)
- .setDuration(mShortAnimationDuration)
- .setListener(null);
- // Animate the "hide" view to 0% opacity. After the animation ends, set its visibility
- // to GONE as an optimization step (it won't participate in layout passes, etc.)
- hideView.animate()
- .alpha(0f)
- .setDuration(mShortAnimationDuration)
- .setListener(new AnimatorListenerAdapter() {
- @Override
- publicvoid onAnimationEnd(Animator animation) {
- hideView.setVisibility(View.GONE);
- }
- });
- }
private void showContentOrLoadingIndicator(boolean contentLoaded) { // Decide which view to hide and which to show. final View showView = contentLoaded ? mContentView : mLoadingView; final View hideView = contentLoaded ? mLoadingView : mContentView; // Set the "show" view to 0% opacity but visible, so that it is visible // (but fully transparent) during the animation. showView.setAlpha(0f); showView.setVisibility(View.VISIBLE); // Animate the "show" view to 100% opacity, and clear any animation listener set on // the view. Remember that listeners are not limited to the specific animation // describes in the chained method calls. Listeners are set on the // ViewPropertyAnimator object for the view, which persists across several // animations. showView.animate() .alpha(1f) .setDuration(mShortAnimationDuration) .setListener(null); // Animate the "hide" view to 0% opacity. After the animation ends, set its visibility // to GONE as an optimization step (it won't participate in layout passes, etc.) hideView.animate() .alpha(0f) .setDuration(mShortAnimationDuration) .setListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { hideView.setVisibility(View.GONE); } }); }
2.Card Flip
point 2.1
在android 3.0以上,你必须调用invalidateOptionsMenu() 当你要update你的menu时,因为 action bar是一直出现的。
point 2.2
public abstract FragmentTransaction setCustomAnimations(int enter, int exit, int popEnter, int popExit)
Since: API Level 13Set specific animation resources to run for the fragments that are entering and exiting in this transaction. The popEnter
and popExit
animations will be played for enter/exit operations specifically when popping the back stack.
这是一个卡片翻转正背面切换的效果,做的其实一般。
[java] view plain copy print ?- if (savedInstanceState == null) {
- // If there is no saved instance state, add a fragment representing the
- // front of the card to this activity. If there is saved instance state,
- // this fragment will have already been added to the activity.
- getFragmentManager()
- .beginTransaction()
- .add(R.id.container, new CardFrontFragment())
- .commit();
- } else {
- mShowingBack = (getFragmentManager().getBackStackEntryCount() > 0);
- }
- // Monitor back stack changes to ensure the action bar shows the appropriate
- // button (either "photo" or "info").
- getFragmentManager().addOnBackStackChangedListener(this);
if (savedInstanceState == null) { // If there is no saved instance state, add a fragment representing the // front of the card to this activity. If there is saved instance state, // this fragment will have already been added to the activity. getFragmentManager() .beginTransaction() .add(R.id.container, new CardFrontFragment()) .commit(); } else { mShowingBack = (getFragmentManager().getBackStackEntryCount() > 0); } // Monitor back stack changes to ensure the action bar shows the appropriate // button (either "photo" or "info"). getFragmentManager().addOnBackStackChangedListener(this);
主要还是这个函数,它和onBackStackChanged(), popBackStack()配合,这一点值得学习。
- privatevoid flipCard() {
- if (mShowingBack) {
- getFragmentManager().popBackStack();
- return;
- }
- // Flip to the back.
- mShowingBack = true;
- // Create and commit a new fragment transaction that adds the fragment for the back of
- // the card, uses custom animations, and is part of the fragment manager's back stack.
- getFragmentManager()
- .beginTransaction()
- .setCustomAnimations(
- R.animator.card_flip_right_in, R.animator.card_flip_right_out,
- R.animator.card_flip_left_in, R.animator.card_flip_left_out)
- // Replace any fragments currently in the container view with a fragment
- .replace(R.id.container, new CardBackFragment())
- // Add this transaction to the back stack, allowing users to press Back
- // to get to the front of the card.
- .addToBackStack(null)
- // Commit the transaction.
- .commit();
- // Defer an invalidation of the options menu (on modern devices, the action bar). This
- // can't be done immediately because the transaction may not yet be committed. Commits
- // are asynchronous in that they are posted to the main thread's message loop.
- mHandler.post(new Runnable() {
- @Override
- publicvoid run() {
- invalidateOptionsMenu();
- }
- });
- }
private void flipCard() { if (mShowingBack) { getFragmentManager().popBackStack(); return; } // Flip to the back. mShowingBack = true; // Create and commit a new fragment transaction that adds the fragment for the back of // the card, uses custom animations, and is part of the fragment manager's back stack. getFragmentManager() .beginTransaction() .setCustomAnimations( R.animator.card_flip_right_in, R.animator.card_flip_right_out, R.animator.card_flip_left_in, R.animator.card_flip_left_out) // Replace any fragments currently in the container view with a fragment .replace(R.id.container, new CardBackFragment()) // Add this transaction to the back stack, allowing users to press Back // to get to the front of the card. .addToBackStack(null) // Commit the transaction. .commit(); // Defer an invalidation of the options menu (on modern devices, the action bar). This // can't be done immediately because the transaction may not yet be committed. Commits // are asynchronous in that they are posted to the main thread's message loop. mHandler.post(new Runnable() { @Override public void run() { invalidateOptionsMenu(); } }); }[java] view plain copy print ?
- @Override
- publicvoid onBackStackChanged() {
- mShowingBack = (getFragmentManager().getBackStackEntryCount() > 0);
- // When the back stack changes, invalidate the options menu (action bar).
- invalidateOptionsMenu();
- }
@Override public void onBackStackChanged() { mShowingBack = (getFragmentManager().getBackStackEntryCount() > 0); // When the back stack changes, invalidate the options menu (action bar). invalidateOptionsMenu(); }
3.Screen Slide
这个我用过很多次了,复习一遍。
<android.support.v4.view.ViewPager />
private ViewPager mPager;
private PagerAdapter mPagerAdapter;
[java] view plain copy print ?- // Instantiate a ViewPager and a PagerAdapter.
- mPager = (ViewPager) findViewById(R.id.pager);
- mPagerAdapter = new ScreenSlidePagerAdapter(getFragmentManager());
- mPager.setAdapter(mPagerAdapter);
- mPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
- @Override
- publicvoid onPageSelected(int position) {
- // 更新actionbar的menu,可以借鉴
- invalidateOptionsMenu();
- }
- });
// Instantiate a ViewPager and a PagerAdapter. mPager = (ViewPager) findViewById(R.id.pager); mPagerAdapter = new ScreenSlidePagerAdapter(getFragmentManager()); mPager.setAdapter(mPagerAdapter); mPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() { @Override public void onPageSelected(int position) { // 更新actionbar的menu,可以借鉴 invalidateOptionsMenu(); } });[java] view plain copy print ?
- @Override
- publicboolean onCreateOptionsMenu(Menu menu) {
- super.onCreateOptionsMenu(menu);
- getMenuInflater().inflate(R.menu.activity_screen_slide, menu);
- menu.findItem(R.id.action_previous).setEnabled(mPager.getCurrentItem() > 0);
- // 这个很好,我一般就只用上面的,没想到这里还可以这样写
- MenuItem item = menu.add(Menu.NONE, R.id.action_next, Menu.NONE,
- (mPager.getCurrentItem() == mPagerAdapter.getCount() - 1)
- ? R.string.action_finish
- : R.string.action_next);
- item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
- returntrue;
- }
@Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); getMenuInflater().inflate(R.menu.activity_screen_slide, menu); menu.findItem(R.id.action_previous).setEnabled(mPager.getCurrentItem() > 0); // 这个很好,我一般就只用上面的,没想到这里还可以这样写 MenuItem item = menu.add(Menu.NONE, R.id.action_next, Menu.NONE, (mPager.getCurrentItem() == mPagerAdapter.getCount() - 1) ? R.string.action_finish : R.string.action_next); item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM | MenuItem.SHOW_AS_ACTION_WITH_TEXT); return true; }
顺便把这个也贴上吧,要不感觉不完整
[java] view plain copy print ?- @Override
- publicboolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- // Navigate "up" the demo structure to the launchpad activity.
- // See http://developer.android.com/design/patterns/navigation.html for more.
- NavUtils.navigateUpTo(this, new Intent(this, MainActivity.class));
- returntrue;
- case R.id.action_previous:
- // Go to the previous step in the wizard. If there is no previous step,
- // setCurrentItem will do nothing.
- mPager.setCurrentItem(mPager.getCurrentItem() - 1);
- returntrue;
- case R.id.action_next:
- // Advance to the next step in the wizard. If there is no next step, setCurrentItem
- // will do nothing.
- mPager.setCurrentItem(mPager.getCurrentItem() + 1);
- returntrue;
- }
- returnsuper.onOptionsItemSelected(item);
- }
@Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case android.R.id.home: // Navigate "up" the demo structure to the launchpad activity. // See http://developer.android.com/design/patterns/navigation.html for more. NavUtils.navigateUpTo(this, new Intent(this, MainActivity.class)); return true; case R.id.action_previous: // Go to the previous step in the wizard. If there is no previous step, // setCurrentItem will do nothing. mPager.setCurrentItem(mPager.getCurrentItem() - 1); return true; case R.id.action_next: // Advance to the next step in the wizard. If there is no next step, setCurrentItem // will do nothing. mPager.setCurrentItem(mPager.getCurrentItem() + 1); return true; } return super.onOptionsItemSelected(item); }
最后,在加上继承的FragmentStatePagerAdapter 就好了,里面判断并创建显示的 Fragment。
这个create()方法比较有趣,一般都命名为getInstance(),可以看到 fragment传参的是 setArguments() 和 getArguments();
[java] view plain copy print ?- publicstatic ScreenSlidePageFragment create(int pageNumber) {
- ScreenSlidePageFragment fragment = new ScreenSlidePageFragment();
- Bundle args = new Bundle();
- args.putInt(ARG_PAGE, pageNumber);
- fragment.setArguments(args);
- return fragment;
- }
- @Override
- publicvoid onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- mPageNumber = getArguments().getInt(ARG_PAGE);
- }
public static ScreenSlidePageFragment create(int pageNumber) { ScreenSlidePageFragment fragment = new ScreenSlidePageFragment(); Bundle args = new Bundle(); args.putInt(ARG_PAGE, pageNumber); fragment.setArguments(args); return fragment; } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mPageNumber = getArguments().getInt(ARG_PAGE); }
另外,再加一点,在Strings.xml中,
[html] view plain copy print ?- <resourcesxmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <stringname="title_template_step">Step <xliff:gid="step_number">%1$d</xliff:g>: Lorem Ipsum</string>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"><string name="title_template_step">Step <xliff:g id="step_number">%1$d</xliff:g>: Lorem Ipsum</string>[java] view plain copy print ?
- // Set the title view to show the page number.
- ((TextView) rootView.findViewById(android.R.id.text1)).setText(
- getString(R.string.title_template_step, mPageNumber + 1))
// Set the title view to show the page number. ((TextView) rootView.findViewById(android.R.id.text1)).setText( getString(R.string.title_template_step, mPageNumber + 1))
1、xliff:g标签介绍:
xliff:g标签是用于在动态的设置某些值时,需要进行字符串连接,但又不改变在其中的静态的字符常量的值,我们就需要使用此标签。
2、属性介绍
属性id可以随便命名
属性example表示举例说明,可以省略
%n$ms:代表输出的是字符串,n代表是第几个参数,设置m的值可以在输出之前放置空格
%n$md:代表输出的是整数,n代表是第几个参数,设置m的值可以在输出之前放置空格,也可以设为0m,在输出之前放置m个0
%n$mf:代表输出的是浮点数,n代表是第几个参数,设置m的值可以控制小数位数,如m=2.2时,输出格式为00.00
- <stringname="time">当前时间:<xliff:gid="prefix">%1$s</xliff:g>时 <xliff:gid="time">%2$s</xliff:g>分</string>
- //然后通过程序,context.getString(R.string.time,"10","05");
<string name="time">当前时间:<xliff:g id="prefix">%1$s</xliff:g>时 <xliff:g id="time">%2$s</xliff:g>分</string>//然后通过程序,context.getString(R.string.time,"10","05");
将会输出——当前时间:10时05分
4.Zoom
其中包含了很多数学,Yay, Math.
其主要就是一个ImageView到另一个ImageView的比例,距离计算,和动画的设计。
[java] view plain copy print ?- AnimatorSet set = new AnimatorSet();
- set
- .play(ObjectAnimator.ofFloat(expandedImageView, View.X, startBounds.left,
- finalBounds.left))
- .with(ObjectAnimator.ofFloat(expandedImageView, View.Y, startBounds.top,
- finalBounds.top))
- .with(ObjectAnimator.ofFloat(expandedImageView, View.SCALE_X, startScale, 1f))
- .with(ObjectAnimator.ofFloat(expandedImageView, View.SCALE_Y, startScale, 1f));
- set.setDuration(mShortAnimationDuration);
- set.setInterpolator(new DecelerateInterpolator());
- set.addListener(new AnimatorListenerAdapter() {
- @Override
- publicvoid onAnimationEnd(Animator animation) {
- mCurrentAnimator = null;
- }
- @Override
- publicvoid onAnimationCancel(Animator animation) {
- mCurrentAnimator = null;
- }
- });
- set.start();
- mCurrentAnimator = set;
AnimatorSet set = new AnimatorSet(); set .play(ObjectAnimator.ofFloat(expandedImageView, View.X, startBounds.left, finalBounds.left)) .with(ObjectAnimator.ofFloat(expandedImageView, View.Y, startBounds.top, finalBounds.top)) .with(ObjectAnimator.ofFloat(expandedImageView, View.SCALE_X, startScale, 1f)) .with(ObjectAnimator.ofFloat(expandedImageView, View.SCALE_Y, startScale, 1f)); set.setDuration(mShortAnimationDuration); set.setInterpolator(new DecelerateInterpolator()); set.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { mCurrentAnimator = null; } @Override public void onAnimationCancel(Animator animation) { mCurrentAnimator = null; } }); set.start(); mCurrentAnimator = set;
5.Layout Changes
一行行许多view的添加和删除的动画效果
用到的是ViewGroup, 但确实没用动画效果
private ViewGroup mContainerView =(ViewGroup) findViewById(R.id.container);
这个R.id.container在布局文件中是一个LinearLayout
[java] view plain copy print ?- privatevoid addItem() {
- // Instantiate a new "row" view.
- final ViewGroup newView = (ViewGroup) LayoutInflater.from(this).inflate(
- R.layout.list_item_example, mContainerView, false);
- // Set the text in the new row to a random country.
- ((TextView) newView.findViewById(android.R.id.text1)).setText(
- COUNTRIES[(int) (Math.random() * COUNTRIES.length)]);
- // Set a click listener for the "X" button in the row that will remove the row.
- newView.findViewById(R.id.delete_button).setOnClickListener(new View.OnClickListener() {
- @Override
- publicvoid onClick(View view) {
- // Remove the row from its parent (the container view).
- // Because mContainerView has android:animateLayoutChanges set to true,
- // this removal is automatically animated.
- mContainerView.removeView(newView);
- // If there are no rows remaining, show the empty view.
- if (mContainerView.getChildCount() == 0) {
- findViewById(android.R.id.empty).setVisibility(View.VISIBLE);
- }
- }
- });
- // Because mContainerView has android:animateLayoutChanges set to true,
- // adding this view is automatically animated.
- mContainerView.addView(newView, 0);
- }
private void addItem() { // Instantiate a new "row" view. final ViewGroup newView = (ViewGroup) LayoutInflater.from(this).inflate( R.layout.list_item_example, mContainerView, false); // Set the text in the new row to a random country. ((TextView) newView.findViewById(android.R.id.text1)).setText( COUNTRIES[(int) (Math.random() * COUNTRIES.length)]); // Set a click listener for the "X" button in the row that will remove the row. newView.findViewById(R.id.delete_button).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { // Remove the row from its parent (the container view). // Because mContainerView has android:animateLayoutChanges set to true, // this removal is automatically animated. mContainerView.removeView(newView); // If there are no rows remaining, show the empty view. if (mContainerView.getChildCount() == 0) { findViewById(android.R.id.empty).setVisibility(View.VISIBLE); } } }); // Because mContainerView has android:animateLayoutChanges set to true, // adding this view is automatically animated. mContainerView.addView(newView, 0); }
只是用ViewGroup的addView()和removeView(),是自带透明度动画效果,不算难。
二.ListViewAnimations 由三部分构成 Google cards example, Animation in adapter, Item manipulation
1.Google card example 这个效果真的很棒
point 1 LruCache
这里面不得不提的就是一个 最核心的类是LruCache (此类在android-support-v4的包中提供)
import android.support.v4.util.LruCache;
首先要初始化:
private LruCache<String, Bitmap> mMemoryCache;
[java] view plain copy print ?- // 获取到可用内存的最大值,使用内存超出这个值会引起OutOfMemory异常。
- // LruCache通过构造函数传入缓存值,以KB为单位。
- int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
- // 使用最大可用内存值的1/8作为缓存的大小。
- int cacheSize = maxMemory / 8;
- mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
- @Override
- protectedint sizeOf(String key, Bitmap bitmap) {
- // 重写此方法来衡量每张图片的大小,默认返回图片数量。
- return bitmap.getByteCount() / 1024;
- }
- };
// 获取到可用内存的最大值,使用内存超出这个值会引起OutOfMemory异常。 // LruCache通过构造函数传入缓存值,以KB为单位。 int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024); // 使用最大可用内存值的1/8作为缓存的大小。 int cacheSize = maxMemory / 8; mMemoryCache = new LruCache<String, Bitmap>(cacheSize) { @Override protected int sizeOf(String key, Bitmap bitmap) { // 重写此方法来衡量每张图片的大小,默认返回图片数量。 return bitmap.getByteCount() / 1024; } };
还要写两个方法:
[java] view plain copy print ?- publicvoid addBitmapToMemoryCache(String key, Bitmap bitmap) {
- if (getBitmapFromMemCache(key) == null) {
- mMemoryCache.put(key, bitmap);
- }
- }
- public Bitmap getBitmapFromMemCache(String key) {
- return mMemoryCache.get(key);
- }
public void addBitmapToMemoryCache(String key, Bitmap bitmap) { if (getBitmapFromMemCache(key) == null) { mMemoryCache.put(key, bitmap); } } public Bitmap getBitmapFromMemCache(String key) { return mMemoryCache.get(key); }
当向 ImageView 中加载一张图片时,首先会在 LruCache 的缓存中进行检查。如果找到了相应的键值,则会立刻更新ImageView ,否则开启一个后台线程来加载这张图片。
- <span style="font-size: 14px;">publicvoid loadBitmap(int resId, ImageView imageView) {
- final String imageKey = String.valueOf(resId);
- final Bitmap bitmap = getBitmapFromMemCache(imageKey);
- if (bitmap != null) {
- imageView.setImageBitmap(bitmap);
- } else {
- imageView.setImageResource(R.drawable.image_placeholder);
- BitmapWorkerTask task = new BitmapWorkerTask(imageView);
- task.execute(resId);
- }
- } </span>
public void loadBitmap(int resId, ImageView imageView) { final String imageKey = String.valueOf(resId); final Bitmap bitmap = getBitmapFromMemCache(imageKey); if (bitmap != null) { imageView.setImageBitmap(bitmap); } else { imageView.setImageResource(R.drawable.image_placeholder); BitmapWorkerTask task = new BitmapWorkerTask(imageView); task.execute(resId); } }
BitmapWorkerTask 还要把新加载的图片的键值对放到缓存中。
[java] view plain copy print ?- <span style="font-size: 14px;">class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {
- // 在后台加载图片。
- @Override
- protected Bitmap doInBackground(Integer... params) {
- final Bitmap bitmap = decodeSampledBitmapFromResource(
- getResources(), params[0], 100, 100);
- addBitmapToMemoryCache(String.valueOf(params[0]), bitmap);
- return bitmap;
- }
- }</span>
class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> { // 在后台加载图片。 @Override protected Bitmap doInBackground(Integer... params) { final Bitmap bitmap = decodeSampledBitmapFromResource( getResources(), params[0], 100, 100); addBitmapToMemoryCache(String.valueOf(params[0]), bitmap); return bitmap; } }
好的,我们现在回到 Google card example
用到库里的很多东西 ,SwingBottomInAnimationAdapter 从下方进入的效果,里面就是用到了使 Y 位移变化的动画
SwipeDismissAdapter 横滑消除的Adapter,其中含有 OnDissmissCallback 接口 ,还有 SwipeDismissListViewTouchListener
OnDismissCallback 是横滑删除的接口类 ; 在 GoogleCardAdapter中包含对LruCache的使用。
[java] view plain copy print ?- ListView listView = (ListView) findViewById(R.id.activity_googlecards_listview);
- mGoogleCardsAdapter = new GoogleCardsAdapter(this);
- SwingBottomInAnimationAdapter swingBottomInAnimationAdapter = new SwingBottomInAnimationAdapter(
- new SwipeDismissAdapter(mGoogleCardsAdapter, this));
- swingBottomInAnimationAdapter.setListView(listView);
- listView.setAdapter(swingBottomInAnimationAdapter);
- mGoogleCardsAdapter.addAll(getItems());
ListView listView = (ListView) findViewById(R.id.activity_googlecards_listview);mGoogleCardsAdapter = new GoogleCardsAdapter(this);SwingBottomInAnimationAdapter swingBottomInAnimationAdapter = new SwingBottomInAnimationAdapter(new SwipeDismissAdapter(mGoogleCardsAdapter, this));swingBottomInAnimationAdapter.setListView(listView);listView.setAdapter(swingBottomInAnimationAdapter);mGoogleCardsAdapter.addAll(getItems());
2.AnimationInExamples
是item view 出现的例子,有 SwingBottomIn,SwingRightIn,SwingLeftIn,SwingBottomRightIn,ScaleIn
SwingBottomIn 就是ListView+ Adapter, 只是这个Adapter被专门的效果Adapter所包裹。
[java] view plain copy print ?- BaseAdapter mAdapter = createListAdapter();
- SwingBottomInAnimationAdapter swingBottomInAnimationAdapter = new SwingBottomInAnimationAdapter(
- mAdapter);
- swingBottomInAnimationAdapter.setListView(getListView());
- getListView().setAdapter(swingBottomInAnimationAdapter);
BaseAdapter mAdapter = createListAdapter();SwingBottomInAnimationAdapter swingBottomInAnimationAdapter = new SwingBottomInAnimationAdapter(mAdapter);swingBottomInAnimationAdapter.setListView(getListView());getListView().setAdapter(swingBottomInAnimationAdapter);
三, ExpandingCell
附:ListView添加不同布局的item
http://www.eoeandroid.com/thread-72369-1-1.html
http://blog.csdn.net/lihonghao1017/article/details/10172493
很好的文章,记录开源项目的;
http://blog.tisa7.com/android_open_source_projects
原文:http://blog.csdn.net/mennoa/article/details/18708209
更多相关文章
- android随意记
- Android(安卓)剪切板操作
- Android(安卓)拖拽
- Android使用自定义AlertDialog
- android 背景圆角以及图片圆角处理
- Android储存BMP格式图片
- shape等特殊xml
- Android(安卓)拖拽
- [转]android 一直在最前面的浮动窗口效果