利用FloatingActionButton+ValueAnimator 完成卫星菜单效果
来源:互联网 发布:手机淘宝店铺头像 编辑:程序博客网 时间:2024/05/21 06:59
前言:卫星菜单其实已经很常见了,网上也有很多教程甚至都有开源的控件了。嫌麻烦自己写的可以直接取拿来用。接下来文章会简单说明实现的过程。
github开源库:https://github.com/oguzbilgener/CircularFloatingActionMenu
这个效果很不错,需要的朋友可以去看看
正文之前先说说FloatingActionButton到底是什么吧,相信还是有部分朋友并不太清楚。
- FloatingActionButton(FAB悬浮按钮) 是 Android 5.0 新特性——Material Design
中的一个控件,是一种悬浮的按钮。 - FloatingActionButton 是 ImageView 的子类,因此它具备ImageView的全部属性。
- FloatingActionButton 结合 CoordinatorLayout 使用,即可实现悬浮在任意控件的任意位置。
- 使用 FloatingActionButton 的难点主要是布局,其在JAVA代码中的用法和普通的 ImageView 基本相同。
跟所有MD控件一样,要使用FAB,需要在gradle文件中先注册依赖:
compile 'com.android.support:design:25.0.0'// FAB 基本属性:// android:src:FAB中显示的图标// app:backgroundTint:正常的背景颜色// app:rippleColor:按下时的背景颜色// app:elevation:正常的阴影大小// app:pressedTranslationZ:按下时的阴影大小// app:layout_anchor:设置FAB的锚点,即以哪个控件为参照设置位置// app:layout_anchorGravity:FAB相对于锚点的位置// app:fabSize:FAB的大小,normal或mini(对应56dp和40dp)// 注意:要想让FAB显示点击后的颜色和阴影变化效果,必须设置onClick事件
想进一步了解FloatingActionButton的可以去看看鸿洋大神的博客:
http://blog.csdn.net/lmj623565791/article/details/46678867
好,FloatingActionButton知道是什么了后我们回到卫星菜单上面来。
其实卫星菜单的效果就是当我们点击主菜单之后弹出附属的子item菜单,再次点击收回子item菜单。那么就会考虑到这么几点:
1.定位Item(设置每一个菜单项的位置)
2.展开Item(动画效果实现,包括菜单按钮旋转动画、菜单项平移、旋转动画、菜单项缩放、透明度变换动画等,这里我们只做平移效果)
3.收回Item
定位涉及到的方法一共有下面几个:参考http://blog.csdn.net/jason0539/article/details/42743531
//view获取自身坐标:getLeft(),getTop(),getRight(),getBottom()//view获取自身宽高:getHeight(),getWidth()//motionEvent获取坐标:getX(),getY(),getRawX(),getRawY()//getTop:获取到的,是view自身的顶边到其父布局顶边的距离//getLeft:获取到的,是view自身的左边到其父布局左边的距离//getRight:获取到的,是view自身的右边到其父布局左边的距离//getBottom:获取到的,是view自身的底边到其父布局顶边的距离//getX():获取点击事件相对控件左边的x轴坐标,即点击事件距离控件左边的距离//getY():获取点击事件相对控件顶边的y轴坐标,即点击事件距离控件顶边的距离//getRawX():获取点击事件相对整个屏幕左边的x轴坐标,即点击事件距离整个屏幕左边的距离//getRawY():获取点击事件相对整个屏幕顶边的y轴坐标,即点击事件距离整个屏幕顶边的距离
文字或许不太理解,那么我们上图
展开Item
需要做些什么呢,这里我们以子item为3举例说明:
根据上图可以清晰的看出来当子item菜单为3个的时候,子itemA应该是左移M单位(M为我们自己设置的长度);子itemC上移M单位;重点为子itemB的位置,由图可以知道当我们以初始item(以下用O代替),子itemB和坐标轴来画一个三角形的话,就可以根据三角函数sin与cos来知道子itemB的坐标。∠AOC为90°,OB平分∠AOC,即∠BOC = (∠AOC/2)=45° ,由三角函数可以很简单的得到B相对于O 左移了M*sin(45°)距离,上移了M*cos(45°) 距离。 以此可以推导当子item为4的时候只需要根据个数算出彼此之间的角度大小,然后同理运用三角函数可以得到位移之后的坐标。
**
收回item
**
相对于展开,收回要简单多了。
展开后我们可以分别得到每个子item的位置坐标,和初始点的位置坐标,那么就可以利用平移动画将其移动回初始点即可。
代码部分:
xml布局代码:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" xmlns:app="http://schemas.android.com/apk/res-auto"> <android.support.design.widget.FloatingActionButton android:id="@+id/item1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_alignParentRight="true" android:layout_marginBottom="20dp" android:layout_marginRight="16dp" android:src="@mipmap/ic_launcher" app:fabSize="mini"/> <android.support.design.widget.FloatingActionButton android:id="@+id/item2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_alignParentRight="true" android:layout_marginBottom="20dp" android:layout_marginRight="16dp" android:src="@mipmap/ic_launcher" app:fabSize="mini"/> <android.support.design.widget.FloatingActionButton android:id="@+id/item3" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_alignParentRight="true" android:layout_marginBottom="20dp" android:layout_marginRight="16dp" android:src="@mipmap/ic_launcher" app:fabSize="mini"/> <android.support.design.widget.FloatingActionButton android:id="@+id/fab" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_alignParentRight="true" android:layout_marginBottom="20dp" android:layout_marginRight="16dp" android:src="@mipmap/ic_launcher" app:fabSize="mini"/></RelativeLayout>
Activity代码:
@ContentView(R.layout.activity_fab)public class FABActivity extends BaseActivity { @ViewInject(R.id.fab) private FloatingActionButton FABButton; @ViewInject(R.id.item1) private FloatingActionButton Item1; @ViewInject(R.id.item2) private FloatingActionButton Item2; @ViewInject(R.id.item3) private FloatingActionButton Item3; //菜单是否展开 private boolean menuOpen = false; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } //点击事件 @Event(R.id.fab) private void fab(View view) { if (menuOpen == false) { showMenu();//展开 } else { hideMenu();//收回 } } //展开菜单 private void showMenu() { //设置为展开菜单 menuOpen = true; //获取1°的值,后面动画移动会用到 final double r = Math.PI / 180; //取得主菜单坐标 int x = (int) FABButton.getX(); int y = (int) FABButton.getY(); //设置第一个子菜单x轴移动动画 ValueAnimator v1 = ValueAnimator.ofInt(x, x - 200);//起始位置主菜单x坐标,终位置向左移200 v1.setDuration(500); v1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { int l = (int) animation.getAnimatedValue(); int t = (int) Item1.getY(); int r = Item1.getWidth() + l; int b = Item1.getHeight() + t; Item1.layout(l, t, r, b); } }); //设置第二个子菜单x轴与y轴移动动画 ValueAnimator v2x = ValueAnimator.ofInt(x, x - (int) (200 * Math.sin(45 * r)));//起始位置主菜单x坐标,终位置向左移200*sin(45°) ValueAnimator v2y = ValueAnimator.ofInt(y, y - (int) (200 * Math.cos(45 * r)));//起始位置主菜单x坐标,终位置向左移200*cos(45°) v2x.setDuration(500).addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { int l = (int) animation.getAnimatedValue(); int t = (int) Item2.getY(); int r = Item2.getWidth() + l; int b = Item2.getHeight() + t; Item2.layout(l, t, r, b); } }); v2y.setDuration(500).addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { int l = (int) Item2.getX(); int t = (int) animation.getAnimatedValue(); int r = Item2.getWidth() + l; int b = Item2.getHeight() + t; Item2.layout(l, t, r, b); } }); //设置第三个子菜单y轴移动动画 ValueAnimator v3 = ValueAnimator.ofInt(y, y - 200);//起始位置主菜单y坐标,终位置向上移200 v3.setDuration(500).addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { int l = (int) Item3.getX(); int t = (int) animation.getAnimatedValue(); int r = Item3.getWidth() + l; int b = Item3.getHeight() + t; Item3.layout(l, t, r, b); } }); //开始上面设置好的展开动画 v1.start(); v2x.start(); v2y.start(); v3.start(); } //收回菜单 private void hideMenu() { //设置为收回菜单 menuOpen = false; //获取现在第一个子菜单的x轴坐标 int x = (int) Item1.getX(); ValueAnimator v1 = ValueAnimator.ofInt(x, (int) FABButton.getX());//始:现x坐标; 终:主菜单x坐标 v1.setDuration(500); v1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { int l = (int) animation.getAnimatedValue(); int t = (int) Item1.getY(); int r = Item1.getWidth() + l; int b = Item1.getHeight() + t; Item1.layout(l, t, r, b); } }); //获取现在第二个子菜单的x轴,y轴坐标 x = (int) Item2.getX(); int y = (int) Item2.getY(); ValueAnimator v2x = ValueAnimator.ofInt(x, (int) FABButton.getX()); ValueAnimator v2y = ValueAnimator.ofInt(y, (int) FABButton.getY()); v2x.setDuration(500).addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { int l = (int) animation.getAnimatedValue(); int t = (int) Item2.getY(); int r = Item2.getWidth() + l; int b = Item2.getHeight() + t; Item2.layout(l, t, r, b); } }); v2y.setDuration(500).addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { int l = (int) Item2.getX(); int t = (int) animation.getAnimatedValue(); int r = Item2.getWidth() + l; int b = Item2.getHeight() + t; Item2.layout(l, t, r, b); } }); //获取现在第三个子菜单的y轴坐标 y = (int) Item3.getY(); ValueAnimator v3 = ValueAnimator.ofInt(y, (int) FABButton.getY()); v3.setDuration(500).addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { int l = (int) Item3.getX(); int t = (int) animation.getAnimatedValue(); int r = Item3.getWidth() + l; int b = Item3.getHeight() + t; Item3.layout(l, t, r, b); } }); //开始设置好的收回动画 v1.start(); v2x.start(); v2y.start(); v3.start(); }}
运行效果:
谢谢大家观看!
为了向别人、向世界证明自己而努力拼搏,而一旦你真的取得了成绩,才会明白:人无须向别人证明什么,只要你能超越自己。
- 利用FloatingActionButton+ValueAnimator 完成卫星菜单效果
- FloatingActionButton 之实现卫星菜单
- 卫星菜单效果实现
- 基于Android的卫星菜单效果实现
- 属性动画实现卫星菜单效果
- RadioGroup 完成功能菜单效果
- 卫星菜单
- 卫星菜单
- 利用FragmentTabHost完成底部菜单
- Android自定义VIew之实现卫星菜单效果
- 利用for循环,完成二级菜单
- 利用pop完成类似倒计时效果
- 利用 CollapsingToolbarLayout 完成联动的动画效果
- 自定义旋转卫星菜单
- Andriod实现卫星菜单
- 卫星式菜单
- 自定义卫星菜单CustomArcMenu
- 仿卫星菜单
- 括号配对问题
- 如何自学Android编程?
- oracle语句中把一列的值合并为一个值
- 设计模式之责任链模式
- 窗口抖动问题思考与解决
- 利用FloatingActionButton+ValueAnimator 完成卫星菜单效果
- IsNull 和 SQL语句中CASE WHEN用法 【转】IsNull 和 SQL语句中CASE WHEN用法收藏 【转】IsNull 和 SQL语句中CASE WHEN用法 1、ISNU
- 学习MySql数据库,包括安装、测试。
- SEO(搜索引擎优化)成败细节的布局,个人理解SEO三大布局思路
- android 关于图片的相关总结
- 类和对象2
- webpack之 code splitting
- ZigBee、WiFi、蓝牙在智能家居应用中的对比
- 初始Redis,redis安装------(一)