您的位置:首页 > 移动开发 > Android开发

android 动态效果学习之旅

2014-01-24 01:16 218 查看
一.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 abstract FragmentTransaction setCustomAnimations (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. The 
popEnter
 and 
popExit
 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);
}


另外,再加一点,在Strings.xml中,
<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, 但确实没用动画效果

private ViewGroup mContainerView =(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;
首先要初始化:
private LruCache<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);

三, 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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: