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 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














  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值