Android自定义VIew实现卫星菜单效果浅析

 一 概述:

最近一直致力于Android自定义VIew的学习,主要在看《android群英传》,还有CSDN博客鸿洋大神和wing大神的一些文章,写的很详细,自己心血来潮,学着写了个实现了类似卫星效果的一个自定义的View,分享到博客上,望各位指点一二。写的比较粗糙,见谅。(因为是在Linux系统下写的,效果图我直接用手机拍的,难看,大家讲究下就看个效果,勿喷)。

先来看个效果图,有点不忍直视:

自定义VIew准备:

(1)创建继承自View的类;

(2)重写构造函数;

(3)定义属性。

(4)重写onMeasure(),onLayout()方法。

好了,废话不说了,准备上菜。

二 相关实现

首先是自定义的View,重写构造函数,我这里是直接继承的VIewGroup,贴上代码:

public MoonView(Context context) {
this(context,null);
}
public MoonView(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public MoonView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}

这里需要读取自定义的属性,所以调用含三个参数的构造函数。

自定义的属性,我这里知定义了两个,一个是菜单弧形的半径,还有个是菜单在屏幕的位置,这里可以设置在左上角,左下角,右上角,右下角。代码如下:

<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="MoonAttrs">
<attr name="mRadius" format="integer"></attr><!--菜单圆形半径-->
<attr name="mPosition"><!--卫星菜单屏幕所在位置-->
<enum name="leftTop" value="-2"></enum><!--左上角-->
<enum name="leftBottom" value="-1"></enum><!--左下角-->
<enum name="rightTop" value="-3"></enum><!--右上角-->
<enum name="rightBottom" value="-4"></enum><!--右下角-->
</attr>
</declare-styleable>
</resources>

然后在布局文件里面引用自定义的View,配置属性:

<?xml version="1.0" encoding="utf-8"?>
<com.example.liujibin.testmyview3.myView.MoonView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res/com.example.liujibin.testmyview3"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
custom:mRadius="400"
custom:mPosition="rightBottom"
>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@mipmap/sapi_icon_add_account"/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@mipmap/sapi_icon_add_account"/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@mipmap/sapi_icon_add_account"/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@mipmap/sapi_icon_add_account"/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@mipmap/sapi_icon_add_account"/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@mipmap/sapi_icon_add_account"/>
</com.example.liujibin.testmyview3.myView.MoonView>

最后我们需要在自定义的View类中的构造函数里,获取相关的属性值:

public MoonView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
//获取相关属性
TypedArray ta = context.getTheme().obtainStyledAttributes(attrs, R.styleable.MoonAttrs,
defStyleAttr,0);
mRaius = ta.getInt(R.styleable.MoonAttrs_mRadius,500);
position = ta.getInt(R.styleable.MoonAttrs_mPosition,-1);
}

做完以上的准备工作,我们就可以对组件进行测量,布局。

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
count = getChildCount()-1;
angle = 90/(count-1); 

int count = getChildCount();
for(int i =0;i< count;i++){
measureChild(getChildAt(i),widthMeasureSpec,heightMeasureSpec);
}
}

count获取按钮的数量,有一个是中心点,不参与计算,angle是每个按钮离基准线的角度,这里以90度为准,固定在这个范围里面均匀分配。

首先先把中心点固定好位置:

@Override
protected void onLayout(boolean b, int i, int i1, int i2, int i3) {
if(isChanged){
layoutBottom();
}
}
private void layoutBottom(){
View view = getChildAt(0);
switch (position){
case -1:
btml = 0;
btmt = getMeasuredHeight() - view.getMeasuredHeight();
btmr = view.getMeasuredWidth();
btmb = getMeasuredHeight();
break;
case -2:
btml = 0;
btmt = 0;
btmr = view.getMeasuredWidth();
btmb = view.getMeasuredHeight();
break;
case -3:
btml = getMeasuredWidth() - view.getMeasuredWidth();
btmt = 0;
btmr = getMeasuredWidth();
btmb = view.getMeasuredHeight();
break;
case -4:
btml = getMeasuredWidth() - view.getMeasuredWidth();
btmt = getMeasuredHeight() - view.getMeasuredHeight();
btmr = getMeasuredWidth();
btmb = getMeasuredHeight();
break;
}
btmWidth = view.getMeasuredWidth();
btmHeight = view.getMeasuredHeight();
view.setOnClickListener(this);
view.layout(btml,btmt,btmr,btmb);
}

position的值看属性就明白了,对中心点进行固定位置。并且注册点击事件。

现在开始给剩下的按钮布局,并隐藏按钮:

@Override
protected void onLayout(boolean b, int i, int i1, int i2, int i3) {
if(isChanged){
layoutBottom();
int count = getChildCount();
for(int k = 0;k < count - 1;k++){
View view = getChildAt(k+1);
int childWidth = view.getMeasuredWidth();
int childHeight = view.getMeasuredHeight();
int childX = (int)(mRaius*(Math.sin(angle*(k)*Math.PI/180)));
int childY = (int)(mRaius*(Math.cos(angle*(k)*Math.PI/180)));
int left = 0;
int top = 0;
int right = 0;
int bottom = 0;
switch(position){
case -1:
left = childX+btmWidth/2-childWidth/2;
top =getMeasuredHeight() - (childY+childHeight/2+btmHeight/2);
right = childX+btmWidth/2+childWidth/2;
bottom =getMeasuredHeight() - (childY + btmHeight/2) + childHeight/2;
break;
case -2:
left = childX+btmWidth/2-childWidth/2;
top =childY-childHeight/2+btmHeight/2;
right = childX+btmWidth/2+childWidth/2;
bottom = childY + btmHeight/2 + childHeight/2;
break;
case -3:
left = getMeasuredWidth() - (childX+btmWidth/2+childWidth/2);
top =childY-childHeight/2+btmHeight/2;
right = getMeasuredWidth() - (childX+btmWidth/2+childWidth/2)+childWidth;
bottom = childY + btmHeight/2 + childHeight/2;
break;
case -4:
left = getMeasuredWidth() - (childX+btmWidth/2+childWidth/2);
top =getMeasuredHeight() - (childY+childHeight/2+btmHeight/2);
right = getMeasuredWidth() - (childX+btmWidth/2+childWidth/2)+childWidth;
bottom =getMeasuredHeight() - (childY + btmHeight/2) + childHeight/2;
break;
}
view.layout(left,top,right,bottom);
view.setVisibility(View.GONE);
}
}
}

现在我们实现点击事件:

@Override
public void onClick(View view) {
if(isChanged){
int count = getChildCount();
for(int i = 0;i < count - 1;i++){
View childView = getChildAt(i+1);
int childX = (int)(mRaius*(Math.sin(angle*(i)*Math.PI/180)));
int childY = (int)(mRaius*(Math.cos(angle*(i)*Math.PI/180)));
int childWidth = view.getMeasuredWidth();
int childHeight = view.getMeasuredHeight();
int left = 0;
int top = 0;
TranslateAnimation ta = null;
switch(position){
case -1:
left = childX+btmWidth/2-childWidth/2;
top =getMeasuredHeight() - (childY+childHeight/2+btmHeight/2);
ta = new TranslateAnimation(-(left+childView.getMeasuredWidth()),0,getMeasuredHeight()-top,0);
break;
case -2:
left = childX+btmWidth/2-childWidth/2;
top =childY-childHeight/2+btmHeight/2;
ta = new TranslateAnimation(-(left+childView.getMeasuredWidth()),0,-top,0);
break;
case -3:
left = getMeasuredWidth() - (childX+btmWidth/2+childWidth/2);
top =childY-childHeight/2+btmHeight/2;
ta = new TranslateAnimation(getMeasuredWidth()-(left+childView.getMeasuredWidth()),0,-top,0);
break;
case -4:
left = getMeasuredWidth() - (childX+btmWidth/2+childWidth/2);
top =getMeasuredHeight() - (childY+childHeight/2+btmHeight/2);
ta = new TranslateAnimation(getMeasuredWidth()-(left+childView.getMeasuredWidth()),0,getMeasuredHeight()-top,0);
break;
}
ta.setDuration(500);
childView.setAnimation(ta);
childView.setVisibility(View.VISIBLE);
}
isChanged = false;
}else{
int count = getChildCount();
for(int i = 0;i < count - 1;i++){
View childView = getChildAt(i+1);
int childX = (int)(mRaius*(Math.sin(angle*(i)*Math.PI/180)));
int childY = (int)(mRaius*(Math.cos(angle*(i)*Math.PI/180)));
int childWidth = view.getMeasuredWidth();
int childHeight = view.getMeasuredHeight();
int left = 0;
int top = 0;
TranslateAnimation ta = null;
switch(position){
case -1:
left = childX+btmWidth/2-childWidth/2;
top =getMeasuredHeight() - (childY+childHeight/2+btmHeight/2);
ta = new TranslateAnimation(0,-(left+childView.getMeasuredWidth()),0,getMeasuredHeight()-top);
break;
case -2:
left = childX+btmWidth/2-childWidth/2;
top =childY-childHeight/2+btmHeight/2;
ta = new TranslateAnimation(0,-(left+childView.getMeasuredWidth()),0,-top);
break;
case -3:
left = getMeasuredWidth() - (childX+btmWidth/2+childWidth/2);
top =childY-childHeight/2+btmHeight/2;
ta = new TranslateAnimation(0,getMeasuredWidth()-(left+childView.getMeasuredWidth()),0,-top);
break;
case -4:
left = getMeasuredWidth() - (childX+btmWidth/2+childWidth/2);
top =getMeasuredHeight() - (childY+childHeight/2+btmHeight/2);
ta = new TranslateAnimation(0,getMeasuredWidth()-(left+childView.getMeasuredWidth()),0,getMeasuredHeight()-top);
break;
}
ta.setDuration(500);
childView.setAnimation(ta);
childView.setVisibility(View.GONE);
}
isChanged = true;
}
}

设置点击显示以及隐藏,并且带飘动的动画效果。

四个角落效果如下:

以上所述是小编给大家介绍的Android自定义VIew实现卫星菜单效果浅析,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!

(0)

相关推荐

  • Android卫星菜单效果的实现方法

    Android小白第一次写博客,心情无比激动.下面给大家展示一下卫星菜单的实现. 1.简单介绍卫星菜单 在应用程序中,有很多展示菜单的方式,但其功能都是大同小异,这样一来,菜单的美观以及展示方式就显的尤为重要,卫星菜单就是很不错的一种.下面是本案例的gif图: 2.学习本案例需要的知识点 (1)动画 (2)自定义ViewGroup (3)自定义属性 a.attr.xml b.在布局中使用自定义属性 c.在代码中获取自定义属性值 3.首先分析我们的卫星菜单需要那些自定义属性并书写代码 首先,菜单可

  • Android 自定义组件卫星菜单的实现

    卫星菜单 ArcMenu 相信大家接触安卓,从新手到入门的过渡,就应该会了解到卫星菜单.抽屉.Xutils.Coolmenu.一些大神封装好的一些组件.这些组件在 Github 上面很容易搜得到,但是有时候打开会发现看不懂里面的代码,包括一些方法和函数 ..... 首先先上效果图: 实现效果 首先如果要想自定义组件 1.那么第一件事就是赋予自定义组件的属性,从效果图上看出,该组件可以存在屏幕的各个角落点,那么位置是其属性之一. 2.既然是卫星菜单,那么主按钮和其附属的小按钮之间的围绕半径也应该作

  • Android自定义VIew实现卫星菜单效果浅析

     一 概述: 最近一直致力于Android自定义VIew的学习,主要在看<android群英传>,还有CSDN博客鸿洋大神和wing大神的一些文章,写的很详细,自己心血来潮,学着写了个实现了类似卫星效果的一个自定义的View,分享到博客上,望各位指点一二.写的比较粗糙,见谅.(因为是在Linux系统下写的,效果图我直接用手机拍的,难看,大家讲究下就看个效果,勿喷). 先来看个效果图,有点不忍直视: 自定义VIew准备: (1)创建继承自View的类; (2)重写构造函数; (3)定义属性. (

  • Android自定义View实现弹性小球效果

    照例先看效果图 自定义代码示例 public class BezierView extends View { Paint paint;//画笔 Path path;//路径 int radius = 50;//圆的半径 int time = 100;//计数时长 int index; int offsetIndex; float viewX, viewY;//图形中心点坐标 float width;//屏幕宽度 float partWidth;//屏幕宽度的1/4 int paddingLeft

  • Android自定义View实现折线图效果

    下面就是结果图(每种状态用一个表情图片表示): 一.主页面的布局文件如下: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height=&quo

  • Android自定义View实现拖拽效果

    腾讯QQ有那种红点拖动效果,今天就来实现一个简单的自定义View拖动效果,再回到原处,并非完全仿QQ红点拖动. 先来看一下效果图 简单说一下实现步骤 1.创建一个类继承View 2.绘制出一个小球 3.重写onTouchEvent,来根据手指放下,移动,抬起,来控制小球 4.直接在布局中引用 先贴一张图看下View的坐标系 下面就贴一下代码,最后会给出源码 public class CustomView extends View { private int lastX; private int

  • Android自定义view之围棋动画效果的实现

    前言 废话不多说直接开始 老规矩,文章最后有源码 完成效果图 棋子加渐变色 棋子不加渐变色 一.测量 1.获取宽高 @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); mWidth = w; mHeight = h; useWidth = mWidth; if (mWidth > mHeight) { useWidth =

  • Android自定义view之3D正方体效果实例

    目录 前言 一.小提 二.将传感器改成事件分发机制 三.使用 四.源码 总结 前言 在之前写了一篇关于3D效果的文章,借助传感器展示,有小伙伴问可不可以改成手势滑动操作(事件分发),所以出一篇文章 传感器相关文章链接:Android 3D效果的实现 一.小提 相对于常见的自定义view而言,继承的GLSurfaceView只有两个构造函数.可以理解为没有提供获取自定义属性的方法. public TouchSurfaceView(Context context) { super(context);

  • Android自定义View实现标签流效果

    本文实例为大家分享了Android自定义View实现标签流效果的具体代码,供大家参考,具体内容如下 一.概述 Android自定义View实现标签流效果,一行放不下时会自动换行,用户可以自己定义单个标签的样式,可以选中和取消,可以监听单个标签的点击事件,功能还算强大,可以满足大部分开发需求,值得推荐,效果图如下: 二.实现代码 1.自定义View 定义属性文件 <declare-styleable name="FlowTagView">         <attr n

  • Android自定义View实现数字雨效果的全过程

    目录 效果图 实现步骤 总结 效果图 在安卓中多种类型的动画,有帧动画.补间动画.属性动画,除此之外,使用自定义的View结合数学公式,就可以绘制出复杂的界面或者动画.这篇文章记录的是仿照黑客帝国的数字雨,来看看效果吧. 实现步骤 准备工作,常量的配置信息 // 文字的颜色值 final int DEFAULT_TEXT_COLOR = Color.argb(255, 0, 255, 70); // 文字大小 final int TEXT_SIZE = 24; // 普通画笔 Paint mPa

  • android自定义View实现跑马灯效果

    android自带的TextView可以实现跑马灯效果,但是有很多的局限性:比如需要设置ellipsize="marquee",获取 focusable="true",设置singleLine="true",控件里的内容需要超过控件本身的长度,无法控制滚动速度和滚动暂停和继续滚动功能,各种限制导致用起来特别不顺手,几乎无法使用到生产环境中,在此背景下,需要自定义View实现跑马灯效果. 使用主要方法:自定义View重写onDraw方法,通过can

  • Android自定义view实现滑动解锁效果

    本文实例为大家分享了Android自定义view实现滑动解锁的具体代码,供大家参考,具体内容如下 1. 需求如下: 近期需要做一个类似屏幕滑动解锁的功能,右划开始,左划暂停. 2. 需求效果图如下 3. 实现效果展示 4. 自定义view如下 /** * Desc 自定义滑动解锁View * Author ZY * Mail sunnyfor98@gmail.com * Date 2021/5/17 11:52 */ @SuppressLint("ClickableViewAccessibili

随机推荐

其他