Android 实现卫星菜单
步骤:一:自定义ViewGroup
1、自定义属性
a、attr.xml
b、在布局文件中使用activity_main.xml
c、在自定义控件中进行读取
2、onMeasure
3、onLayout
4、设置主按钮的旋转动画
为menuItem添加平移动画和旋转动画
实现menuItem的点击事件
MainActivity.java
public class MainActivity extends AppCompatActivity {private ListView listView;private List<String> mData;private ArrayAdapter mAdapter;private ArcMenuActivity mArc;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);listView = (ListView) findViewById(R.id.listview);mArc = (ArcMenuActivity) findViewById(R.id.view_arc);addData();mAdapter = new ArrayAdapter<String>(MainActivity.this, android.R.layout.simple_list_item_1, mData);listView.setAdapter(mAdapter);listView.setOnScrollListener(new AbsListView.OnScrollListener() {@Overridepublic void onScrollStateChanged(AbsListView view, int scrollState) {}@Overridepublic void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {if (mArc.isOpen()) {mArc.toggleMenu(200);}}});mArc.setOnMenuItemClickListener(new ArcMenuActivity.onMenuItemClickListener() {@Overridepublic void onItemClick(View view, int position) {Toast.makeText(MainActivity.this,position+" : "+view.getTag(),Toast.LENGTH_SHORT).show();}});}private void addData() {mData = new ArrayList<String>();for (int i = 'A'; i <= 'z'; i++) {mData.add((char) i + "");}}}
ArcMenuActivity.java
/*** 自定义的ViewGroup,在activity_main.xml里面调用*/ public class ArcMenuActivity extends ViewGroup {private static final int POS_LEFT_TOP = 0;private static final int POS_RIGHT_TOP = 1;private static final int POS_LEFT_BOTTOM = 2;private static final int POS_RIGHT_BOTTOM = 3;private Position mPosition = Position.RIGHT_BOTTOM;private Status mCurrentStatus = Status.CLOSE;private onMenuItemClickListener onMenuItemClick;private View mCButton; //主菜单按钮private int mRadius; //卫星半径//卫星菜单位置枚举类public enum Position {LEFT_TOP, RIGHT_TOP, LEFT_BOTTOM, RIGHT_BOTTOM}//主菜单的状态public enum Status {OPEN, CLOSE}//定义一个点击点击子菜单项的回调接口public interface onMenuItemClickListener {void onItemClick(View view, int position);}//自定义的点击方法public void setOnMenuItemClickListener(onMenuItemClickListener onMenuItemClick) {this.onMenuItemClick = onMenuItemClick;}public ArcMenuActivity(Context context) { // super(context);this(context, null);}public ArcMenuActivity(Context context, AttributeSet attrs) { // super(context, attrs);this(context, attrs, 0);}public ArcMenuActivity(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);//获取自定义属性的值TypedArray ta = context.getTheme().obtainStyledAttributes(attrs, R.styleable.ArcMenu, defStyleAttr, 0);//getInt()方法//参数1:所需要赋予给pos的值// 参数2:如果参数1无值,则取该值,就是custom:position="right_bottom"没有定义时int pos = ta.getInt(R.styleable.ArcMenu_position, POS_RIGHT_BOTTOM);switch (pos) {case POS_LEFT_TOP:mPosition = Position.LEFT_TOP;break;case POS_LEFT_BOTTOM:mPosition = Position.LEFT_BOTTOM;break;case POS_RIGHT_TOP:mPosition = Position.RIGHT_TOP;break;case POS_RIGHT_BOTTOM:mPosition = Position.RIGHT_BOTTOM;break;}//半径的默认值mRadius = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 100, getResources().getDisplayMetrics());//getDimension()方法//参数1:所需要赋予给radius的值// 参数2:如果参数1无值,则取该值,就是custom:radius="100"没有定义时mRadius = (int) ta.getDimension(R.styleable.ArcMenu_radius, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 100, getResources().getDisplayMetrics()));//radius输出的值为pxLog.v("TGA", "position = " + mPosition + ",radius = " + mRadius);ta.recycle();}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {//获取activity_main.xml里面的View控件的个数// <my.com.example.x550v.view.ArcMenuActivity/>里面的int count = getChildCount();//测量childfor (int i = 0; i < count; i++) {//xml文件里面控件的位置,宽,高 measureChild(getChildAt(i), widthMeasureSpec, heightMeasureSpec);}super.onMeasure(widthMeasureSpec, heightMeasureSpec);}@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {if (changed) {//主菜单按钮 layoutCButton();//子菜单按钮 subItemButton();}}//定义主菜单按钮private void layoutCButton() {//或者使用findViewById()的方法mCButton = getChildAt(0); //获取第一个xml文件里面的第一个View控件mCButton.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {//主菜单动画//这里得使用getContext()来获取contextAnimation animation = AnimationUtils.loadAnimation(getContext(), R.anim.anim);//如果使用setAnimation()只会转一次 mCButton.startAnimation(animation);//子菜单动画toggleMenu(200);}});//l为主菜单距离父布局的左边距离,t为主菜单距离父布局的顶边距离int l = 0, t = 0;//获取主按钮的宽和高int width = mCButton.getMeasuredWidth();int height = mCButton.getMeasuredHeight();switch (mPosition) {case LEFT_TOP://0,0表示坐上角的位置l = 0;t = 0;break;case RIGHT_TOP:l = getMeasuredWidth() - width; //getMeasuredWidth()取得容器的宽度t = 0;break;case LEFT_BOTTOM:l = 0;t = getMeasuredHeight() - height; //getMeasuredHeight()取得容器的高度break;case RIGHT_BOTTOM:l = getMeasuredWidth() - width;t = getMeasuredHeight() - height;break;}mCButton.layout(l, t, l + width, t + height);}//定义子菜单按钮public void subItemButton() {//获取activity_main.xml里面的View控件的个数// <my.com.example.x550v.view.ArcMenuActivity/>里面的int count = getChildCount();for (int i = 0; i < count - 1; i++) { //去掉主菜单按钮的一个View child = getChildAt(i + 1); //从第一个子菜单开始获取,而不是主菜单//开始时设置子菜单为隐藏 child.setVisibility(GONE);//当子菜单为左上角时,cl为子菜单距离父布局的左边距离,ct为子菜单距离父布局的顶边距离//当子菜单为右上角时,cl为子菜单距离父布局的右边距离,ct为子菜单距离父布局的顶边距离//当子菜单为左下角时,cl为子菜单距离父布局的左边距离,ct为子菜单距离父布局的底边距离//当子菜单为右下角时,cl为子菜单距离父布局的右边距离,ct为子菜单距离父布局的底边距离//Math.PI的值为圆周率pai,角度为180度//Math.PI / 2 / (count - 2)是取出平均角,//*i是看子菜单拥有几个平均角int cl = (int) (mRadius * Math.sin(Math.PI / 2 / (count - 2) * i)); // Log.v("TAG","cl = "+cl);int ct = (int) (mRadius * Math.cos(Math.PI / 2 / (count - 2) * i));//获取子菜单View的宽和高int cWidth = child.getMeasuredWidth();int cHeight = child.getMeasuredHeight();//如果子菜单在左下,右下if (mPosition == Position.LEFT_BOTTOM || mPosition == Position.RIGHT_BOTTOM) {ct = getMeasuredHeight() - cHeight - ct;Log.v("TAG","getMeasuredHeight()"+getMeasuredHeight());}//如果子菜单在右上,右下if (mPosition == Position.RIGHT_TOP || mPosition == Position.RIGHT_BOTTOM) {cl = getMeasuredWidth() - cWidth - cl;}child.layout(cl, ct, cl + cWidth, ct + cHeight);}}//定义点击主菜单后子菜单出现动画public void toggleMenu(int duration) {int count = getChildCount();for (int i = 0; i < count - 1; i++) {final View childView = getChildAt(i + 1);childView.setVisibility(View.VISIBLE);//end 0,0//startint cl = (int) (mRadius * Math.sin(Math.PI / 2 / (count - 2) * i));int ct = (int) (mRadius * Math.cos(Math.PI / 2 / (count - 2) * i));int xFlag = 1;int yFlag = 1;if (mPosition == Position.LEFT_TOP || mPosition == Position.LEFT_BOTTOM) {xFlag = -1;}if (mPosition == Position.LEFT_TOP || mPosition == Position.RIGHT_TOP) {yFlag = -1;}final AnimationSet animationSet = new AnimationSet(true);//位移动画Animation tranAnim = null;//如果为关闭状态,点击后会散开if (mCurrentStatus == Status.CLOSE) {//子菜单一开始就是扇形排布,其坐标为(0,0)tranAnim = new TranslateAnimation(xFlag * cl, 0, yFlag * ct, 0);childView.setClickable(true);childView.setFocusable(true);}//否则为打开状态,点击后会收缩else {tranAnim = new TranslateAnimation(0, xFlag * cl, 0, yFlag * ct);childView.setClickable(false);childView.setFocusable(false);}tranAnim.setFillAfter(true);tranAnim.setDuration(duration);tranAnim.setStartOffset((i * 100) / count); //越是后面的子菜单,延迟越多tranAnim.setAnimationListener(new Animation.AnimationListener() {@Overridepublic void onAnimationStart(Animation animation) {}@Overridepublic void onAnimationEnd(Animation animation) {if (mCurrentStatus == Status.CLOSE) {childView.setVisibility(GONE);}}@Overridepublic void onAnimationRepeat(Animation animation) {}});//旋转动画RotateAnimation rotateAnim = new RotateAnimation(0, 360, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);rotateAnim.setFillAfter(true);rotateAnim.setDuration(duration);//先旋转,再位移//先位移,再旋转更炫 // animationSet.addAnimation(tranAnim); animationSet.addAnimation(rotateAnim);animationSet.addAnimation(tranAnim);childView.startAnimation(animationSet);final int pos = i + 1;//子菜单的点击监听childView.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {if (onMenuItemClick != null) {onMenuItemClick.onItemClick(childView, pos);}menuItemAnim(pos - 1); //子菜单点击动画 changeStatus();}});}//切换菜单状态,在for()循环之外 changeStatus();}//切换菜单状态private void changeStatus() {mCurrentStatus = (mCurrentStatus == Status.CLOSE ? Status.OPEN : Status.CLOSE);}//添加子菜单点击动画private void menuItemAnim(int pos) {for (int i = 0; i < getChildCount() - 1; i++) {View childView = getChildAt(i + 1);if (i == pos) {childView.startAnimation(scaleBigAnimation(300));} else {childView.startAnimation(scaleSmallAnimation(300));}childView.setClickable(false);childView.setFocusable(false);}}//子菜单变大,变小动画private Animation scaleBigAnimation(int duration) {AnimationSet set = new AnimationSet(true);Animation scaleAnim = new ScaleAnimation(1, 2, 1, 2, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);Animation alphaAnim = new AlphaAnimation(1, 0);set.setDuration(duration);set.addAnimation(scaleAnim);set.addAnimation(alphaAnim);set.setFillAfter(true);return set;}private Animation scaleSmallAnimation(int duration) {AnimationSet set = new AnimationSet(true);Animation scaleAnim = new ScaleAnimation(1, 0, 1, 0, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);Animation alphaAnim = new AlphaAnimation(1, 0);set.setDuration(duration);set.addAnimation(scaleAnim);set.addAnimation(alphaAnim);set.setFillAfter(true);return set;}public boolean isOpen(){return mCurrentStatus == Status.OPEN;}}
activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:custom="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><ListViewandroid:id="@+id/listview"android:layout_width="match_parent"android:layout_height="match_parent"/><my.com.example.x550v.view.ArcMenuActivityandroid:id="@+id/view.arc"android:layout_width="match_parent"android:layout_height="match_parent"custom:position="right_bottom"custom:radius="200dp"><RelativeLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@drawable/composer_button"><ImageViewandroid:id="@+id/iv_button"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerInParent="true"android:src="@drawable/composer_icn_plus" /></RelativeLayout><ImageViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:src="@drawable/composer_camera"android:tag="Camera" /><ImageViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:src="@drawable/composer_music"android:tag="Music" /><ImageViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:src="@drawable/composer_place"android:tag="Place" /><ImageViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:src="@drawable/composer_sleep"android:tag="Sleep" /><ImageViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:src="@drawable/composer_thought"android:tag="Thought" /><ImageViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:src="@drawable/composer_with"android:tag="With" /></my.com.example.x550v.view.ArcMenuActivity></RelativeLayout>
attr.xml
<resources><attr name="position"><enum name="left_top" value="0" /><enum name="right_top" value="1" /><enum name="left_bottom" value="2" /><enum name="right_bottom" value="3" /></attr><attr name="radius" format="dimension" /><declare-styleable name="ArcMenu"><attr name="position" /><attr name="radius" /></declare-styleable></resources>
anim.xml
<setxmlns:android="http://schemas.android.com/apk/res/android"><rotateandroid:duration="500"android:fromDegrees="0"android:toDegrees="360"android:pivotX="50%"android:pivotY="50%"android:fillAfter="true"/> </set>
运行效果:
转载于:https://www.cnblogs.com/tianhengblogs/p/5263186.html
Android 实现卫星菜单相关推荐
- android 开发卫星菜单,android之类似卫星菜单,来自定义ViewGroup。。。。。
这是一个继承ViewGroup的自定义控件,对于高手来说比较简单,但对于我们这样的小白,确实是一个不错的demo 定义继承ViewGroup的自定义View ,需要实现它的两个基本方法, onMea ...
- android 实现自定义卫星菜单
看了hyman老师的视频,听起来有点迷糊,所以就想把实现卫星菜单的实现总结一下.长话短说,下面总结一下: 一.自定义ViewGroup 1).自定义属性文件 属性的定义: <attr name= ...
- android 弹出菜单环形,『Android自定义View实战』实现一个小清新的弹出式圆环菜单...
前言 Android表现快捷菜单的形式有很多种,比如使用PopupWindow弹出来的小弹窗,类似QQ的侧拉功能菜单,以及之前讲过的弧形菜单( Android 自定义弧形旋转菜单栏--卫星菜单),这次 ...
- android用户界面之菜单(Menu)教程实例汇总
一.Menu的基本介绍 1.从头学Android之Menu选项菜单 http://www.apkbus.com/android-13930-1-1.html 2.Android 界面之Menu菜单 ...
- Android双向滑动菜单完全解析,教你如何一分钟实现双向滑动特效
转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/9671609 记得在很早之前,我写了一篇关于Android滑动菜单的文章,其中有一个 ...
- android的选项菜单,Android界面菜单(2)—选项菜单
选项菜单 Android 4.0 系统中,Activity在创建时便会调用 onCreateOptionMenu() 函数初始化自身的菜单系统.在Activity的整个生命周期中,选项菜单是一直被重复 ...
- android 按钮 菜单,(期末要考啊)Android的menu(菜单)按钮的使用
(期末要考啊)Android的menu(菜单)按钮的使用 安卓 Android的菜单按钮 使用xml的方式创建菜单项在res下的menu目录下新建一个main.xml文件,以menu为根节点,添加一个 ...
- android 动态修改菜单,如何在Android的“选项”菜单上更改MenuItem?
如何在Android的"选项"菜单上更改MenuItem? 我的Activity上有一个选项菜单,带有mymenu.xml"开始". 选择此3000128611 ...
- android自定义侧滑菜单代码,原生Android 侧滑菜单实践(部分)
此为第一个制作侧滑菜单的实践 . 此部分仅仅为部分实践: 仅缺menu的字符串布局,以及需要修改的MainActivity.java文件,也是需要主要修改的地方. 从使用MD设计-进行侧滑菜单的制作( ...
最新文章
- 爱奇艺火爆的背后,个性化推荐排序是如何配合的?
- torch topk
- 电脑屏幕保护怎么取消_怎么监控员工电脑?老板如何知道员工上班在干什么?...
- 自定义的Sort对象
- 区块链宠物社区Pawtocol与去中心化社交网络memeunity达成合作
- SAP License:物料账错误描述与解决办法
- Kafka 的生产者优秀架构设计
- Ubuntu上安装GCC编译器
- u8系统怎么进服务器取数,u8服务器如何连接数据库
- [转]如何学好windows c++编程 学习精髓(收集,整理)
- MySQL的安装与配置——详细教程
- java calendar星期几_java使用Calendar类判断今天是星期几
- java jit_Java的JIT
- SCAU 2018新生赛 初出茅庐 全题解
- 大数据时代:大数据发展必备三个条件
- Excel 中的协方差阵
- 盘点抖音上的整蛊程序,会了这些谁还敢跟你玩?小心没朋友啦
- 用MATLAB读取.nc文件,并绘图
- conrestoneSVN的登录,使用自行解决,嘻嘻
- iphone4s改装 linux,iPhone4S降级教程(支持iOS5.1.1)可实现完美越狱
热门文章
- mybatisplus报的mysql错误归纳
- 请用旧版的 Scala-2.11 搭配 Spark-2.4.8 / hadoop-2.7
- VirtualBox扩容失败-Progress state: VBOX_E_NOT_SUPPORTED
- Golang服务端开发及微服务架构
- Kubernetes的client-go库介绍
- Android图表引擎AChartEngine - 简介
- 【java学习之路】(java框架)007.IoC和DI注解开发
- mysql replication 延时_MySQL:延迟的主从复制 ( Delayed Replication )
- 查询Linux的公网及内网IP
- hive 中String对长度没有限制