前言
由于工作需要,小编对最近十分炫酷的android动画效果进行了一波疯狂搜集。经过一下午的努力,小编终于成功的将大部分好看的动画浏览了一遍,差点闪瞎我的24k钛合金狗眼。所以,小编本着渴望装逼的心情,将好的动画的实现原理,所使用的框架一个一个的整理出来。逼王之路,指日可待!!!
正文
今天小编带给各位大佬的是侧滑菜单+圆形揭示动画的实现。废话少说,看效果先。
怎么样?是不是很炫酷?下面我们就一起来看看这个效果是如何实现的?
动画实现方式
点击demo地址获得实现代码。
关于动画实现其实十分简单。
- 导入库:
在文件的build.gradle文件中添加以下内容:
repositories {
maven {
url "https://jitpack.io"
}
}
dependencies {
compile 'com.github.ozodrukh:CircularReveal:1.0.4'
compile 'com.github.yalantis:Side-Menu.Android:1.0.1'
}
- 主布局文件
我们需要在主布局文件中进行以下内容添加:
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<io.codetail.widget.RevealFrameLayout
android:id="@+id/container_frame"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="@+id/content_overlay"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"/>
<LinearLayout
android:id="@+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"/>
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:minHeight="?attr/actionBarSize"
android:background="?attr/colorPrimary"/>
</io.codetail.widget.RevealFrameLayout>
<ScrollView
android:id="@+id/scrollView"
android:scrollbarThumbVertical="@android:color/transparent"
android:layout_width="@dimen/sliding_menu_width"
android:layout_height="match_parent"
android:layout_gravity="start|bottom">
<LinearLayout
android:id="@+id/left_drawer"
android:orientation="vertical"
android:layout_width="@dimen/sliding_menu_width"
android:layout_height="wrap_content"
android:divider="@android:color/transparent"
android:background="@android:color/transparent">
</LinearLayout>
</ScrollView>
</android.support.v4.widget.DrawerLayout>
我们也看到了,主布局文件相当简单。其中content_overlay
层盖在content_frame
之上,显示圆形揭露效果。left_drawer
盛放多个菜单项。
- 新建fragment
此处我们需要新建一个fragment来盛放需要展示的内容,也就是可以使用圆形揭露方式进行内容刷新,切换的区域。需要注意的是,此fragment必须实现ScreenShotable接口。而ScreenShotable内部只包含两个抽象方法如下:
//此方法将此时fragment区域的View做了一个截图并保存到ContentFragment.this.bitmap
@Override
public void takeScreenShot() {
Thread thread = new Thread() {
@Override
public void run() {
Bitmap bitmap = Bitmap.createBitmap(containerView.getWidth(),
containerView.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
containerView.draw(canvas);
ContentFragment.this.bitmap = bitmap;
}
};
thread.start();
}
//这里提供了可以从外界获取ContentFragment.this.bitmap的方法。
@Override
public Bitmap getBitmap() {
return bitmap;
}
- 圆形揭示动画
上述动图所展示圆形揭示效果就由下面代码完成。
//此处进行fragment的图片的替换
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private ScreenShotable replaceFragment(ScreenShotable screenShotable, int topPosition) {
this.res = this.res == R.drawable.content_music ? R.drawable.content_films : R.drawable.content_music;
View view = findViewById(R.id.content_frame);
int finalRadius = Math.max(view.getWidth(), view.getHeight());
//这里定义圆形揭露动画。
Animator animator = ViewAnimationUtils.createCircularReveal(view, 0, topPosition, 0, finalRadius);
animator.setInterpolator(new AccelerateInterpolator());
animator.setDuration(ViewAnimator.CIRCULAR_REVEAL_ANIMATION_DURATION);
//在动画执行前将之前获得的fragment区域的截图覆盖到真正的fragment之上。
findViewById(R.id.content_overlay).setBackgroundDrawable(new BitmapDrawable(getResources(), screenShotable.getBitmap()));
animator.start();
//在动画执行中更换真正的新的fragment。
ContentFragment contentFragment = ContentFragment.newInstance(this.res);
getSupportFragmentManager().beginTransaction().replace(R.id.content_frame, contentFragment).commit();
return contentFragment;
}
- 侧滑菜单实现
看完了上述代码,我们圆形揭示的动画效果的核心部分已经结束,接下来我们看一下侧滑菜单以及它是如何与圆形揭露动画交互的。需要实现侧滑菜单,首先需要在Activity实现接口ViewAnimator.ViewAnimatorListener
,ViewAnimator
类就是我们上面通过compile 'com.github.yalantis:Side-Menu.Android:1.0.1'
导入的类。在使用时,我们需要实例化一个ViewAnimator
类的实例,并且在侧滑菜单开始滑动时,调用showMenuContent
方法。那么如何启动侧滑菜单并且监听呢?答案就是ActionBarDrawerToggle
,具体代码如下:
private void setActionBar() {
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
//定义左上角图标是否可以点击
getSupportActionBar().setHomeButtonEnabled(true);
//在左边添加向左箭头返回键
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
//注册侧滑菜单监听器
drawerToggle = new ActionBarDrawerToggle(
this,/* host Activity */
drawerLayout,/* DrawerLayout object */
toolbar, /* nav drawer icon to replace 'Up' caret */
R.string.drawer_open, /* "open drawer" description */
R.string.drawer_close /* "close drawer" description */
) {
//当侧滑菜单关闭时
@Override
public void onDrawerClosed(View view) {
super.onDrawerClosed(view);
linearLayout.removeAllViews();
linearLayout.invalidate();
}
//当侧滑菜单滑动时
@Override
public void onDrawerSlide(View drawerView, float slideOffset) {
super.onDrawerSlide(drawerView, slideOffset);
if (slideOffset > 0.6 && linearLayout.getChildCount() == 0)
viewAnimator.showMenuContent();
}
//当侧滑菜单打开时
@Override
public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(drawerView);
}
};
drawerLayout.setDrawerListener(drawerToggle);
}
值得注意的是ActionBarDrawerToggle
只能在onPostCreate
和onConfigurationChanged
之间使用。
//当onCreate彻底执行完毕
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
//ActionBarDrawerToggle的syncState()方法会和Toolbar关联,将图标放入到Toolbar上。
drawerToggle.syncState();
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
//当状态改变时图标也改变
drawerToggle.onConfigurationChanged(newConfig);
}
经过上述代码我们可以知道该动画通过activity中对侧滑菜单状态进行监听,实现关于侧滑菜单的动效。而实现部分全部放在ViewAnimator
之中,那么我们来看看ViewAnimator
内部都做了什么?从调用方式就可以知道,其中只有一个外部方法那就是showMenuContent
。
public void showMenuContent() {
setViewsClickable(false);
viewList.clear();
double size = list.size();
for (int i = 0; i < size; i++) {
View viewMenu = appCompatActivity.getLayoutInflater().inflate(R.layout.menu_list_item, null);
final int finalI = i;
//为viewMenu添加事件监听
viewMenu.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int[] location = {0, 0};
v.getLocationOnScreen(location);
switchItem(list.get(finalI), location[1] + v.getHeight() / 2);
}
});
((ImageView) viewMenu.findViewById(R.id.menu_item_image)).setImageResource(list.get(i).getImageRes());
viewMenu.setVisibility(View.GONE);
viewMenu.setEnabled(false);
viewList.add(viewMenu);
animatorListener.addViewToContainer(viewMenu);
final double position = i;
final double delay = 3 * ANIMATION_DURATION * (position / size);
//执行逐个滑出动画并保存每个fragment当前显示的截图。
new Handler().postDelayed(new Runnable() {
public void run() {
if (position < viewList.size()) {
animateView((int) position);
}
if (position == viewList.size() - 1) {
screenShotable.takeScreenShot();
setViewsClickable(true);
}
}
}, (long) delay);
}
}
上述代码一共做了两件事,第一件:为viewMenu添加事件监听,第二件,执行逐个滑出动画并保存每个fragment当前显示的截图。其中进行圆形揭示的方法为
private void switchItem(Resourceble slideMenuItem, int topPosition) {
this.screenShotable = animatorListener.onSwitch(slideMenuItem, screenShotable, topPosition);
hideMenuContent();
}
我们可以看到,它就是调用了我们在Activity中实现的接口方法onSwitch
执行揭露动画,之后执行侧滑菜单退回的动画。
最后我们来看看其余三个接口方法是干嘛的:
@Override
public void disableHomeButton() {
//定义左上角图标是否可以点击
getSupportActionBar().setHomeButtonEnabled(false);
}
@Override
public void enableHomeButton() {
getSupportActionBar().setHomeButtonEnabled(true);
drawerLayout.closeDrawers();
}
@Override
public void addViewToContainer(View view) {
linearLayout.addView(view);
}
剩余的三个接口方法其实就是对toolbar按钮的一些控制,还有对侧滑菜单区域view的管理。内容很简单,就不细说了。
总述
终于搞完了,可能是第一次总结这种类型的东西,总感觉有点繁杂,还是希望帮到大家。
文章参考
//www.greatytc.com/p/d2b1689a23bf
https://github.com/Yalantis/Side-Menu.Android