android 动态效果学习之旅
一.Android官网上training的这个实例项目 com.example.android.animationsdemo.MainActivity
里面有5种4.0以上的实例效果
1.Simple Crossfade
这是一个文字从无到有逐渐显现的效果,没什么说的,就是一个函数
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 abstractFragmentTransactionsetCustomAnimations(int enter, int exit, int popEnter, int popExit)
Since: API Level 13 Set specific animation resources to run for the fragments that are entering and exiting in this transaction. ThepopEnter
andpopExit
animations will be played for enter/exit operations specifically when popping the back stack.
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()配合,这一点值得学习。
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(); } }); }
@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;
// 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(); } });
@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; }顺便把这个也贴上吧,要不感觉不完整
@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();
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); }
<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>
// 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
<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的比例,距离计算,和动画的设计。
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, 但确实没用动画效果
privateViewGroupmContainerView =(ViewGroup) findViewById(R.id.container);
这个R.id.container在布局文件中是一个LinearLayout
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;
首先要初始化:
privateLruCache<String,Bitmap>mMemoryCache;
// 获取到可用内存的最大值,使用内存超出这个值会引起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; } };还要写两个方法:
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 ,否则开启一个后台线程来加载这张图片。
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 还要把新加载的图片的键值对放到缓存中。
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的使用。
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所包裹。
BaseAdapter mAdapter = createListAdapter();SwingBottomInAnimationAdapter swingBottomInAnimationAdapter = new SwingBottomInAnimationAdapter(mAdapter);swingBottomInAnimationAdapter.setListView(getListView());getListView().setAdapter(swingBottomInAnimationAdapter);
附: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
更多相关文章
- Android(安卓)ScrollView嵌套Webview(实际使用CoordinatorLayout
- 填充Listview第一个Item的分隔线
- android 控件放大缩小效果实现
- Android(安卓)TabHost的使用(一)
- Android(安卓)对话框用法
- android > WebView > 获取表单数据
- 【Android】Android开源项目分类汇总
- Android——TextView指定字符串颜色高亮,实现类似微信、支付宝搜
- Android(安卓)仿58同城进度条加载内容动画效果的实现