卫星式菜单的总结。

 关于做卫星式菜单的总结。

首先做这个的思路:
一、动画
    主要动画为点击主按钮时主按钮的旋转,子按钮以一定半径弹射出去,子按钮弹出过程中,伴随有旋转效果。收缩后会消失。

    总结为:

         1、主按钮相应点击事件旋转。

         2、子按钮弹出时旋转,收回后消失。
二、自定义ViewGroup
    1、自定义属性
        a、attr.xml
        b、在布局文件中使用

        c、在自定义控件中进行读取

         这一部分是为了可以以后可以修改,具体实现参照代码

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:alex="http://schemas.android.com/apk/res/com.example.arcmenu" 
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
    
    <ListView 
        android:id="@+id/listview"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"/>

    <com.example.arcmenu.view.ArcMenu
        android:id="@+id/menu"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        alex:position="right_bottom"
        alex:radius="150dp" >

        <ImageView
            android:id="@+id/button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" 
            android:src="@drawable/main"/>
         ..........
  </com.example.arcmenu.view.ArcMenu>
</RelativeLayout>
其中第三行 对自定义资源的引用不可缺少

    2、onMeasure

在自定义ViewGroup中,不需要再这个方法中作过多操作。

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
	{
		int count = getChildCount();

		for (int i = 0; i < count; i++)
		{
			// 测量child
			measureChild(getChildAt(i), widthMeasureSpec, widthMeasureSpec);
		}
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
	}


    3、onLayout

在该方法中,需要对每个控件,即每个按钮进行布局

protected void onLayout(boolean changed, int l, int t, int r, int b)
	{
		if (changed)
		{
			layoutCButton();

			// 定位六个子itemmenu,以逆时针排布
			int count = getChildCount();

			for (int i = 0; i < count - 1; i++)
			{
				View child = getChildAt(i + 1);
				child.setVisibility(View.GONE);

				// 通过三角函数,计算位置
				int cl = (int) (mRadius * Math.sin(Math.PI / 2 / (count - 2)
						* i));
				int ct = (int) (mRadius * Math.cos(Math.PI / 2 / (count - 2)
						* i));

				int cWidth = child.getMeasuredWidth();
				int cHeight = child.getMeasuredHeight();
				// 左下右下
				if (mPosition == Position.LEFT_BOTTOM
						|| mPosition == Position.RIGHT_BOTTOM)
				{
					ct = getMeasuredHeight() - cHeight - ct;
				}
				// 右上右下
				if (mPosition == Position.RIGHT_TOP
						|| mPosition == Position.RIGHT_BOTTOM)
				{
					cl = getMeasuredWidth() - cWidth - cl;
				}
				child.layout(cl, ct, cl + cWidth, ct + cHeight);
			}
		}
	}

private void layoutCButton()
    {
        // 没有作有多少个子布局的判断。可以在onMeasure里面判断有多少个,不够就new一个异常
        mCButton = getChildAt(0);
        mCButton.setOnClickListener(this);
        // 定位CButton需要他的layout(l,t,r,b)
        int l = 0;
        int t = 0;

        int width = mCButton.getMeasuredWidth();
        int height = mCButton.getMeasuredHeight();

        switch (mPosition)
        {
        case LEFT_TOP:
            l = 0;
            t = 0;
            break;
        case LEFT_BOTTOM:
            l = 0;
            t = getMeasuredHeight() - height;
            break;
        case RIGHT_TOP:
            l = getMeasuredWidth() - width;
            t = 0;
            break;
        case RIGHT_BOTTOM:
            l = getMeasuredWidth() - width;
            t = getMeasuredHeight() - height;
            break;
        }
        mCButton.layout(l, t, l + width, t + width);
    }


通过计算并且对主按钮的POSITION判断,得出每个ChildView应该放置的位置。
	private void rotateCButton(View v, float start, float end, int duration)
	{
		RotateAnimation anim = new RotateAnimation(start, end,
				Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
				0.5f);
		anim.setDuration(duration);
		anim.setFillAfter(true);
		v.startAnimation(anim);
	}


    4、设置主按钮旋转动画 ,为menuitem设置平移动画和旋转动画。(可以在布局文件里设置ID,可以通过getChildAt(0)获取,可以在onMeasure里面设置ID(不会)。

       主按钮的旋转动画和子按钮的旋转平移动画是分开写的。

主按钮的

	private void rotateCButton(View v, float start, float end, int duration)
	{
		RotateAnimation anim = new RotateAnimation(start, end,
				Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
				0.5f);
		anim.setDuration(duration);
		anim.setFillAfter(true);
		v.startAnimation(anim);
	}
子按钮:
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);
			Log.e("TAG1", "" + 1);

			int 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;
			}

			AnimationSet animset = new AnimationSet(true);
			Animation tranAnim = null;
			// to open
			if (mCurrentStatus == Status.CLOSE)
			{
				tranAnim = new TranslateAnimation(Xflag * cl, 0, Yflag * ct, 0);
				childview.setFocusable(true);
				childview.setClickable(true);
			} else
			// to close
			{
				tranAnim = new TranslateAnimation(0, Xflag * cl, 0, Yflag * ct);
				childview.setFocusable(false);
				childview.setClickable(false);
			}
			
			tranAnim.setDuration(duration);
			tranAnim.setFillAfter(true);
			tranAnim.setStartOffset((i*100)/count);
			// 一直监听,不是执行完上面才执行这段
			tranAnim.setAnimationListener(new AnimationListener()
			{
				public void onAnimationStart(Animation animation)
				{
				}

				public void onAnimationRepeat(Animation animation)
				{
				}

				public void onAnimationEnd(Animation animation)
				{
					if (mCurrentStatus == Status.CLOSE)
					{
						childview.setVisibility(View.GONE);
					}
				}
			});

			RotateAnimation rotateAnim = new RotateAnimation(0, 720,
					Animation.RELATIVE_TO_SELF, 0.5f,
					Animation.RELATIVE_TO_SELF, 0.5f);
			rotateAnim.setDuration(duration);
			rotateAnim.setFillAfter(true);

			animset.addAnimation(rotateAnim);
			animset.addAnimation(tranAnim);
			childview.startAnimation(animset);

			final int pos = i + 1;
			childview.setOnClickListener(new OnClickListener()
			{
				public void onClick(View v)
				{
					if (mMenuitemClickListener != null)
						mMenuitemClickListener.onClick(childview, pos);

					menuItemAnim(pos - 1);
					changeStatus();
				}
			});
		}
		changeStatus();
	}

togglemenu是响应主按钮点击的方法。

主要内容如上。


在自定义布局中,

	/**
	 * 点击菜单子项的回调接口
	 */
	public interface onMenuitemClickListener
	{
		void onClick(View v, int pos);
	}

	public void setonMenuitemClickListener(
			onMenuitemClickListener mMenuitemClickListener)
	{
		this.mMenuitemClickListener = mMenuitemClickListener;
	}

在activity中就可以通过对象直接调用监听器响应子按钮的点击事件

private ArcMenu mMenu;
...........
mMenu.setonMenuitemClickListener(new onMenuitemClickListener()
		{
			public void onClick(View v, int pos)
			{
				Toast.makeText(MainActivity.this, pos + ":" + v.getTag(),
						Toast.LENGTH_SHORT).show();
			}
		});




内容概要:《2024年中国城市低空经济发展指数报告》由36氪研究院发布,指出低空经济作为新质生产力的代表,已成为中国经济新的增长点。报告从发展环境、资金投入、创新能力、基础支撑和发展成效五个维度构建了综合指数评价体系,评估了全国重点城市的低空经济发展状况。北京和深圳在总指数中名列前茅,分别以91.26和84.53的得分领先,展现出强大的资金投入、创新能力和基础支撑。低空经济主要涉及无人机、eVTOL(电动垂直起降飞行器)和直升机等产品,广泛应用于农业、物流、交通、应急救援等领域。政策支持、市场需求和技术进步共同推动了低空经济的快速发展,预计到2026年市场规模将突破万亿元。 适用人群:对低空经济发展感兴趣的政策制定者、投资者、企业和研究人员。 使用场景及目标:①了解低空经济的定义、分类和发展驱动力;②掌握低空经济的主要应用场景和市场规模预测;③评估各城市在低空经济发展中的表现和潜力;④为政策制定、投资决策和企业发展提供参考依据。 其他说明:报告强调了政策监管、产业生态建设和区域融合错位的重要性,提出了加强法律法规建设、人才储备和基础设施建设等建议。低空经济正加速向网络化、智能化、规模化和集聚化方向发展,各地应找准自身比较优势,实现差异化发展。
数据集一个高质量的医学图像数据集,专门用于脑肿瘤的检测和分类研究以下是关于这个数据集的详细介绍:该数据集包含5249张脑部MRI图像,分为训练集和验证集。每张图像都标注了边界框(Bounding Boxes),并按照脑肿瘤的类型分为四个类别:胶质瘤(Glioma)、脑膜瘤(Meningioma)、无肿瘤(No Tumor)和垂体瘤(Pituitary)。这些图像涵盖了不同的MRI扫描角度,包括矢状面、轴面和冠状面,能够全面覆盖脑部解剖结构,为模型训练提供了丰富多样的数据基础。高质量标注:边界框是通过LabelImg工具手动标注的,标注过程严谨,确保了标注的准确性和可靠性。多角度覆盖:图像从不同的MRI扫描角度拍摄,包括矢状面、轴面和冠状面,能够全面覆盖脑部解剖结构。数据清洗与筛选:数据集在创建过程中经过了彻底的清洗,去除了噪声、错误标注和质量不佳的图像,保证了数据的高质量。该数据集非常适合用于训练和验证深度学习模型,以实现脑肿瘤的检测和分类。它为开发医学图像处理中的计算机视觉应用提供了坚实的基础,能够帮助研究人员和开发人员构建更准确、更可靠的脑肿瘤诊断系统。这个数据集为脑肿瘤检测和分类的研究提供了宝贵的资源,能够帮助研究人员开发出更准确、更高效的诊断工具,从而为脑肿瘤患者的早期诊断和治疗规划提供支持。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值