转载请附上本文链接:http://blog.csdn.net/cyp331203/article/details/40423727

先来看看效果:

一眼看上去好像还挺炫的,感觉比較复杂。。。实际上并不难,以下我们来看看怎样实现:

基本素材就是以下三个:

我们先来看看布局文件怎么写,实际上这里这三张图片都差点儿相同,我们这里使用RelativeLayout,方便兴许小图标的增加,基本就是centerInParentaliagnParentBottom,仅仅是外圈小图标的安排要略微注意一下,这里我们左半边图标以最左边的一个图标为基准,右半边的图标以最右边的一个图标为基准,在这里各自是iv_channel1iv_channel7

<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="match_parent"
tools:context="${relativePackage}.${activityClass}" > <RelativeLayout
android:id="@+id/level1"
android:layout_width="100dp"
android:layout_height="50dp"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:background="@drawable/level1" > <ImageView
android:id="@+id/iv_icon_home"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_centerInParent="true"
android:src="@drawable/icon_home" />
</RelativeLayout> <RelativeLayout
android:id="@+id/level2"
android:layout_width="180dp"
android:layout_height="90dp"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:background="@drawable/level2" > <ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_margin="10dp"
android:src="@drawable/icon_search" >
</ImageView> <ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_margin="10dp"
android:src="@drawable/icon_myyouku" >
</ImageView> <ImageView
android:id="@+id/iv_icon_menu"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="5dp"
android:src="@drawable/icon_menu" /> </RelativeLayout> <RelativeLayout
android:id="@+id/level3"
android:layout_width="260dp"
android:layout_height="130dp"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:background="@drawable/level3" > <ImageView
android:id="@+id/iv_channel1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginBottom="10dp"
android:layout_marginLeft="5dp"
android:src="@drawable/channel1" /> <ImageView
android:id="@+id/iv_channel2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@id/iv_channel1"
android:layout_alignLeft="@id/iv_channel1"
android:layout_marginBottom="7dp"
android:layout_marginLeft="18dp"
android:src="@drawable/channel2" /> <ImageView
android:id="@+id/iv_channel3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@id/iv_channel2"
android:layout_alignLeft="@id/iv_channel2"
android:layout_marginBottom="2dp"
android:layout_marginLeft="35dp"
android:src="@drawable/channel3" /> <ImageView
android:id="@+id/iv_channel4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="5dp"
android:src="@drawable/channel4" /> <ImageView
android:id="@+id/iv_channel7"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_marginBottom="10dp"
android:layout_marginRight="5dp"
android:src="@drawable/channel7" /> <ImageView
android:id="@+id/iv_channel6"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@id/iv_channel7"
android:layout_alignRight="@id/iv_channel7"
android:layout_marginBottom="7dp"
android:layout_marginRight="18dp"
android:src="@drawable/channel6" /> <ImageView
android:id="@+id/iv_channel5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@id/iv_channel6"
android:layout_alignRight="@id/iv_channel6"
android:layout_marginBottom="2dp"
android:layout_marginRight="35dp"
android:src="@drawable/channel5" />
</RelativeLayout> </RelativeLayout>

布局完之后的效果:

之后我们就能够開始着手这个怎么实现,我们的基本想法是(小房子图标所在的为level1,第二圈灰色的部分为level2,最外圈为level3):

1、点击小房子图标,假设level2和level3都处于显示状态,则将这两层都隐藏,假设这两层都不存在,则仅仅将level2显示出来;假设仅仅有level2显示着,那么将level2隐藏

2、点击levle2的”三“字图标,则实现隐藏和显示level3组件

3、点击手机的menu键,则实现假设level1,2,3都处于显示状态,则将三者都隐藏,假设仅仅有level1、level2显示,则将level1、2隐藏,假设仅仅有level1显示,则将level1隐藏;假设没有不论什么level显示着,则将level1和level2显示出来

4、上面的显示和隐藏的过程,都使用动画来实现

基本逻辑关系已经理清楚了,那么如今的问题就在于这个Animation怎样写;显然我们这里需要用到一个RotateAnimation旋转动画,因为这里牵涉到旋出和旋入的效果,我们必需要清楚这个动画的角度是怎样定的,比方从0~180是旋入还是旋出效果?

经过实验,我们发现,RotateAnimation的角度例如以下,我们能够发现,它的角度定义是依照顺时针增长的

那么依照这个角度来看,我们假设想要组件顺时针旋入,同一时候顺时针旋出的话,角度是要怎样确定的呢

从上图能够比較easy看出来,顺时针旋出的话,角度是从0~180度,那么旋入呢?是不是从180~0度?,实际上这里旋入应该是180~360度。

相同的,假设这里想实现逆时针出入的话,角度能够设为0~-180和-180~-360度,留给大家自己试试。

在角度确定好之后呢,我们能够来着手实现动画效果,这里因为三个组件level1、level2、level3的动画都是一致的,所以这里选择使用一个工具类,来实现几个静态方法,来定义动画,达到复用的效果:

工具类例如以下:

package com.alexchen.youkumenuexercise.utils;

import android.view.View;
import android.view.animation.RotateAnimation; public class AnimationUtils {
//旋出的动画,无延迟时间
public static void startAnimationOut(View view) {
startAnimationOut(view, 0); }
//旋入的动画,无延迟时间
public static void startAnimationIn(View view) {
startAnimationIn(view, 0);
} //旋出的动画
//delay为动画延迟的时间,单位是毫秒
public static void startAnimationOut(View view, long delay) {
RotateAnimation animation = new RotateAnimation(0, 180,
view.getWidth() / 2, view.getHeight());
animation.setDuration(500);
animation.setStartOffset(delay);
animation.setFillAfter(true);
view.startAnimation(animation); }
//旋入的动画
//delay为动画延迟的时间,单位是毫秒
public static void startAnimationIn(View view, long delay) {
RotateAnimation animation = new RotateAnimation(180, 360,
view.getWidth() / 2, view.getHeight());
animation.setDuration(500);
animation.setStartOffset(delay);
animation.setFillAfter(true);
view.startAnimation(animation);
} }

当中设置了两个可以延时开启动画的方法,为的是让三个组件进出的时候可以体现出层次感,让用户体验更好。

最后是Activity中的代码,这里没有做不论什么生命周期相关的处理,仅仅是简单的实现功能:

package com.alexchen.youkumenuexercise;

import com.alexchen.youkumenuexercise.utils.AnimationUtils;

import android.app.Activity;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageView;
import android.widget.RelativeLayout; public class MainActivity extends Activity implements OnClickListener { private RelativeLayout level1;
private RelativeLayout level2;
private RelativeLayout level3; private ImageView iv_icon_menu;
private ImageView iv_icon_home;
/**
* 表示level3是否是现状状态,默觉得true
*/
private boolean isLevel3In;
private boolean isLevel2In;
private boolean isLevel1In; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
isLevel3In = true;
isLevel2In = true;
isLevel1In = true;
initViews();
setOnclickListenersForViews();
} /**
* 设置views的监听事件
*/
private void setOnclickListenersForViews() {
iv_icon_home.setOnClickListener(this);
iv_icon_menu.setOnClickListener(this); } /**
* 初始化须要的view组件
*/
private void initViews() {
level1 = (RelativeLayout) findViewById(R.id.level1);
level2 = (RelativeLayout) findViewById(R.id.level2);
level3 = (RelativeLayout) findViewById(R.id.level3);
iv_icon_menu = (ImageView) findViewById(R.id.iv_icon_menu);
iv_icon_home = (ImageView) findViewById(R.id.iv_icon_home);
} /**
* activity响应的点击事件
*/
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.iv_icon_menu:
if (isLevel3In) {
// 假设level3是显示的,那么就让出去
AnimationUtils.startAnimationOut(level3);
isLevel3In = false;
} else {
// 假设level3是不显示的,那么让其进入
AnimationUtils.startAnimationIn(level3);
isLevel3In = true;
} break;
case R.id.iv_icon_home:
if (isLevel2In) {
// 假设level2是显示状态
AnimationUtils.startAnimationOut(level2, 200);
isLevel2In = false;
} else {
AnimationUtils.startAnimationIn(level2);
isLevel2In = true;
}
if (isLevel3In) {
AnimationUtils.startAnimationOut(level3);
isLevel3In = false;
} break; default:
break;
}
} @Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_MENU) {
// 假设是menu键按下的话:
changeLevelState(); }
return super.onKeyDown(keyCode, event);
} /**
* 改变三个圆环的状态
*/
private void changeLevelState() {
if (isLevel1In) {
AnimationUtils.startAnimationOut(level1, 400);
isLevel1In = false;
} else {
AnimationUtils.startAnimationIn(level1);
isLevel1In = true;
}
if (isLevel2In) {
AnimationUtils.startAnimationOut(level2, 200);
isLevel2In = false;
} else {
AnimationUtils.startAnimationIn(level2, 200);
isLevel2In = true;
}
if (isLevel3In) {
AnimationUtils.startAnimationOut(level3);
isLevel3In = false;
}
} }

Android自己定义控件系列一:Android怎样实现老版优酷client三级环形菜单的更多相关文章

  1. Android自己定义控件系列五:自己定义绚丽水波纹效果

    尊重原创!转载请注明出处:http://blog.csdn.net/cyp331203/article/details/41114551 今天我们来利用Android自己定义控件实现一个比較有趣的效果 ...

  2. Android自己定义控件系列二:自己定义开关button(一)

    这一次我们将会实现一个完整纯粹的自己定义控件,而不是像之前的组合控件一样.拿系统的控件来实现.计划分为三部分:自己定义控件的基本部分,自己定义控件的触摸事件的处理和自己定义控件的自己定义属性: 以下就 ...

  3. Android自己定义控件系列案例【五】

    案例效果: 案例分析: 在开发银行相关client的时候或者开发在线支付相关client的时候常常要求用户绑定银行卡,当中银行卡号一般须要空格分隔显示.最常见的就是每4位数以空格进行分隔.以方便用户实 ...

  4. Android自己定义控件系列三:自己定义开关button(二)

    接上一篇自己定义开关button(一)的内容继续.上一次实现了一个开关button的基本功能.即自己定义了一个控件.开关button,实现了点击切换开关状态的功能.今天我们想在此基础之上.进一步实现触 ...

  5. android自己定义控件系列教程----视图

    理解android视图 对于android设备我们所示区域事实上和它在底层的绘制有着非常大的关系,非常多时候我们都仅仅关心我们所示,那么在底层一点它究竟是怎么样的一个东西呢?让我们先来看看这个图. w ...

  6. android自己定义控件系列教程-----仿新版优酷评论剧集卡片滑动控件

    我们先来看看优酷的控件是怎么回事? 仅仅响应最后也就是最顶部的卡片的点击事件,假设点击的不是最顶部的卡片那么就先把它放到最顶部.然后在移动到最前面来.重复如次. 知道了这几条那么我们就非常好做了. 里 ...

  7. Android自己定义控件:老版优酷的三级菜单(效果图 + Demo)

    效果图: 制作思路: 1.先分析这个效果,事实上能够理解为把三级菜单分成level1,level2,level3,level1是始终显示的. 点击level1后,level2会出现:点击level2后 ...

  8. Android自己定义控件皮肤

    Android自己定义控件皮肤 对于Android的自带控件,其外观仅仅能说中规中矩,而我们平时所示Android应用中,一个简单的button都做得十分美观.甚至于很多button在按下时的外观都有 ...

  9. Android自己定义控件:进度条的四种实现方式

    前三种实现方式代码出自: http://stormzhang.com/openandroid/2013/11/15/android-custom-loading/ (源代码下载)http://down ...

随机推荐

  1. Tair是一个高性能,分布式,可扩展,高可靠的key/value结构存储系统(转)

    Tair是一个高性能,分布式,可扩展,高可靠的key/value结构存储系统! Tair专为小文件优化,并提供简单易用的接口(类似Map)Tair支持Java和C版本的客户端 Tair is a di ...

  2. uva Matrix Decompressing (行列模型)

    Matrix Decompressing 题目:    给出一个矩阵的前i行,前j列的和.要求你求出满足的矩阵. 矩阵的数范围在[1,20].   一開始就坑在了这里.没读细致题目. 囧...   事 ...

  3. 用Ajax删除的做法

    一般程序文件代码 using System;using System.Web;using System.Linq;using System.Data.Linq; public class Shanch ...

  4. c#Enum的用法

    public enum ResType { Role = 0, Dept = 1, Group = 2, Site = 3, Org = 4, Sub=8 } 这里定义了一个enum    ResTy ...

  5. Linux程序设计学习笔记----多线程编程线程同步机制之相互排斥量(锁)与读写锁

    相互排斥锁通信机制 基本原理 相互排斥锁以排他方式防止共享数据被并发訪问,相互排斥锁是一个二元变量,状态为开(0)和关(1),将某个共享资源与某个相互排斥锁逻辑上绑定之后,对该资源的訪问操作例如以下: ...

  6. codeforces 325B Stadium and Games

    这道题思路很简单,设刚开始队伍数为d=2^p*x,其中x是奇数,则比赛场次n=(2^p-1)*x+(x-1)*x/2,然后从0开始枚举p的值,接着解一元二次方程x^2+(2^(p+1)-3)x-2*n ...

  7. mvc action 有多种跳转

    在ASP.NET mvc下,action 有多种跳转方式: return RedirectToAction("Index");//一个参数时在本Controller下 如果Redi ...

  8. 事件总线帧---Otto

    我们如果这样一种业务场景.如今在做一款及时聊天应用,我们在聊天页面进行收发信息.同一时候也要实时更新前一页面的聊天记录,这时我们该怎样去实现?说说我曾经的实现策略.我使用的是广播接收器BroadCas ...

  9. hdu 4404 Worms(多边形与圆的交)

    求出爆炸点的坐标,就成了多边形与圆相交面积的模板题了... #include<algorithm> #include<iostream> #include<cstring ...

  10. Android在子线程中更新UI(二)

    MainActivity如下: package cc.testui2; import android.os.Bundle; import android.view.View; import andro ...