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实现卫星菜单效果浅析,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!

时间: 2024-08-03 13:24:45

Android自定义VIew实现卫星菜单效果浅析的相关文章

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

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

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

下面就是结果图(每种状态用一个表情图片表示): 一.主页面的布局文件如下: <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实现弹性小球效果_Android

照例先看效果图 自定义代码示例 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实现水面上涨效果_Android

实现效果如下: 实现思路: 1.如何实现圆中水面上涨效果:利用Paint的setXfermode属性为PorterDuff.Mode.SRC_IN画出进度所在的矩形与圆的交集实现 2.如何水波纹效果:利用贝塞尔曲线,动态改变波峰值,实现"随着进度的增加,水波纹逐渐变小的效果" 话不多说,看代码. 首先是自定义属性值,有哪些可自定义属性值呢? 圆的背景颜色:circle_color,进度的颜色:progress_color,进度显示文字的颜色:text_color,进度文字的大小:tex

Android 自定义view实现水波纹效果

http://blog.csdn.net/tianjian4592/article/details/44222565 在实际的开发中,很多时候还会遇到相对比较复杂的需求,比如产品妹纸或UI妹纸在哪看了个让人兴奋的效果,兴致高昂的来找你,看了之后目的很明确,当然就是希望你能给她: 在这样的关键时候,身子板就一定得硬了,可千万别说不行,爷们儿怎么能说不行呢: 好了,为了让大家都能给妹纸们想要的,后面会逐渐分享一些比较比较不错的效果,目的只有一个,通过自定义view实现我们所能实现的动效: 今天主要分

android自定义view实现progressbar的效果

一键清理是很多Launcher都会带有的功能,其效果也比较美观.实现方式也许有很多中,其中常见的是使用图片drawable来完成的,具体可以参考这篇文章:模仿实现360桌面水晶球式的一键清理特效.本文另辟蹊径,使用自定义View来完成同样的效果,性能.效率更高.   ProgressWheel相信很多人并不陌生,我参考了其中一些代码.有意思的是,看完它的代码,发现其中隐藏了没有使用的矩形进度条,因为项目名字的原因我估计也永远不会出现了吧.所以就在其基础之上增增改改,形成了ProgressRect

Android自定义View实现圆环交替效果_Android

下面请先看效果图: 看上去是不很炫的样子,它的实现上也不是很复杂,重点在与onDraw()方法的绘制. 首先是我们的attrs文件: <?xml version="1.0" encoding="utf-8"?> <resources> <attr name="firstColor" format="color"/> <attr name="secondColor"

Android自定义View实现水面上涨效果

实现效果如下: 实现思路: 1.如何实现圆中水面上涨效果:利用Paint的setXfermode属性为PorterDuff.Mode.SRC_IN画出进度所在的矩形与圆的交集实现 2.如何水波纹效果:利用贝塞尔曲线,动态改变波峰值,实现"随着进度的增加,水波纹逐渐变小的效果" 话不多说,看代码. 首先是自定义属性值,有哪些可自定义属性值呢? 圆的背景颜色:circle_color,进度的颜色:progress_color,进度显示文字的颜色:text_color,进度文字的大小:tex