`
473687880
  • 浏览: 535825 次
文章分类
社区版块
存档分类
最新评论

Android高手进阶教程(二十六)之---Android超仿Path菜单的实现!

 
阅读更多

Hi~大家好,出来创业快3个月了,一切还不错,前一段时间用了业余时间搞了个问答类网站YQMA(http://yqma.net).想做中国的stackoverflow,哈哈,只是YY下,希望大家多多支持!

好了,今天给大家分享的是Path菜单的简单实现,可以支持自定义方向(左上,右上,右下,左下),并且可以自定义菜单的个数,难点就是菜单的摆放位置(动态设置margin),还有动画的实现,其实动画只是简单用了个TranslateAnimation,N个菜单一起移动的时候感觉很cool~

这里也用到了自定义标签,这里不懂的童鞋可以看我 Android高手进阶教程(四)之----Android 中自定义属性(attr.xml,TypedArray)的使用! 这篇文章.好了废话不多说了,

首先创建一个android工程命名为PathTest.目录结构如下图:



第二步:在values文件夹下新建一个attrs.xml文件,代码如下:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="PathMenuView">  
        <attr name="position"> 
            <enum name="left_top" value="0"></enum>
            <enum name="right_top" value="1"></enum>
            <enum name="right_bottom" value="2"></enum>
            <enum name="left_bottom" value="3"></enum>
        </attr>
    </declare-styleable>  
</resources>

第三步:新建一个PathMenuView.java这个就是我们自定义的Path菜单控件,代码如下:

package com.tutor.path;

import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.AnticipateInterpolator;
import android.view.animation.OvershootInterpolator;
import android.view.animation.TranslateAnimation;
import android.widget.FrameLayout;
import android.widget.ImageView;


/**
 * @author frankiewei.
 * 超级仿path菜单
 * position定义菜单的位置,目前支持:左上;右上;右下;左下四个方向。
 * menuResIds定义出现的菜单的资源ID
 */
public class PathMenuView extends FrameLayout {
	
	private static final int LEFT_TOP = 0;
	
	private static final int RIGHT_TOP = 1;
	
	private static final int RIGHT_BOTTOM = 2;
	
	private static final int LEFT_BOTTOM = 3;
	
	
	/**
	 * 默认的位置是在右下角.
	 */
	private int position = 3;
	
	/**
	 * 那个圆形菜单.
	 */
	private ImageView mHome;
	
	/**
	 * 上下文.
	 */
	private Context mContext;
	
	
	/**
	 * 设备的宽度.
	 */
	private int mWIDTH = 0;
	
	/**
	 * 设备的高度.
	 */
	private int mHEIGHT = 0;
	
	/**
	 * 设备的density.
	 */
	private float mDensity;
	
	/**
	 * 菜单是否显示.
	 */
	private boolean bMenuShow;
	
	private static int	xOffset		= 15;
	private static int	yOffset		= -13;
	
	/**
	 * 菜单的资源个数.
	 */
	private int[] menuResIds = {R.drawable.composer_camera,R.drawable.composer_music,
			R.drawable.composer_sleep,R.drawable.composer_music,R.drawable.composer_place};
	

	public PathMenuView(Context context){
		super(context);
		setupViews();
	}
	
	public PathMenuView(Context context, AttributeSet attrs) {
		super(context, attrs);
		TypedArray a = context.obtainStyledAttributes(attrs,  
                R.styleable.PathMenuView);
		
		position = a.getInt(R.styleable.PathMenuView_position,3);
		
		a.recycle();
		setupViews();
	}
	
	private void setupViews(){
		mContext = getContext();

		mHEIGHT = mContext.getResources().getDisplayMetrics().heightPixels;
		mWIDTH = mContext.getResources().getDisplayMetrics().widthPixels;
		mDensity = mContext.getResources().getDisplayMetrics().density;
		
		xOffset = (int) (10.667 * mDensity);
		yOffset = (int) (8.667 * mDensity);
		
		mHome = new ImageView(mContext);
		
		mHome.setImageResource(R.drawable.composer_button);
		mHome.setOnClickListener(listener);
		
		addView(mHome);
		
		LayoutParams mHomeparams = (FrameLayout.LayoutParams)mHome.getLayoutParams();
		mHomeparams.width = LayoutParams.WRAP_CONTENT;
		mHomeparams.height = LayoutParams.WRAP_CONTENT;
		
		switch (position) {
		case LEFT_TOP:
			mHomeparams.gravity = Gravity.LEFT | Gravity.TOP;
			for (int i = 0; i < menuResIds.length; i++) {

				int width_padding = mWIDTH / ((menuResIds.length - 1) * 2);
				int height_padding = mHEIGHT / ((menuResIds.length - 1) * 2);

				ImageView imageView = new ImageView(mContext);
				imageView.setImageResource(menuResIds[i]);
				addView(imageView);
				LayoutParams params = (FrameLayout.LayoutParams) imageView
						.getLayoutParams();
				params.width = LayoutParams.WRAP_CONTENT;
				params.height = LayoutParams.WRAP_CONTENT;
				params.leftMargin = mWIDTH / 2
						- ((menuResIds.length - i - 1) * width_padding);
				params.topMargin = mHEIGHT / 2 - i * height_padding;
				params.gravity = Gravity.LEFT | Gravity.TOP;
				imageView.setLayoutParams(params);

			}
			
			break;
		case RIGHT_TOP:
			mHomeparams.gravity = Gravity.RIGHT | Gravity.TOP;
			for (int i = 0; i < menuResIds.length; i++) {

				int width_padding = mWIDTH / ((menuResIds.length - 1) * 2);
				int height_padding = mHEIGHT / ((menuResIds.length - 1) * 2);

				ImageView imageView = new ImageView(mContext);
				imageView.setImageResource(menuResIds[i]);
				addView(imageView);
				LayoutParams params = (FrameLayout.LayoutParams) imageView
						.getLayoutParams();
				params.width = LayoutParams.WRAP_CONTENT;
				params.height = LayoutParams.WRAP_CONTENT;
				params.rightMargin = mWIDTH / 2
						- ((menuResIds.length - i - 1) * width_padding);
				params.topMargin = mHEIGHT / 2 - i * height_padding;
				params.gravity = Gravity.RIGHT | Gravity.TOP;
				imageView.setLayoutParams(params);

			}
			break;
		case RIGHT_BOTTOM:
			mHomeparams.gravity = Gravity.RIGHT | Gravity.BOTTOM;
			for (int i = 0; i < menuResIds.length; i++) {

				int width_padding = mWIDTH / ((menuResIds.length - 1) * 2);
				int height_padding = mHEIGHT / ((menuResIds.length - 1) * 2);

				ImageView imageView = new ImageView(mContext);
				imageView.setImageResource(menuResIds[i]);
				addView(imageView);
				LayoutParams params = (FrameLayout.LayoutParams) imageView
						.getLayoutParams();
				params.width = LayoutParams.WRAP_CONTENT;
				params.height = LayoutParams.WRAP_CONTENT;
				params.rightMargin = mWIDTH / 2
						- ((menuResIds.length - i - 1) * width_padding);
				params.bottomMargin = mHEIGHT / 2 - i * height_padding;
				params.gravity = Gravity.RIGHT | Gravity.BOTTOM;
				imageView.setLayoutParams(params);

			}
			break;
		case LEFT_BOTTOM:
			mHomeparams.gravity = Gravity.LEFT | Gravity.BOTTOM;
			for(int i = 0; i < menuResIds.length; i++){
				
				int width_padding = mWIDTH / ((menuResIds.length - 1) * 2);
				int height_padding = mHEIGHT / ((menuResIds.length -1) * 2);
				
			    ImageView imageView = new ImageView(mContext);
				imageView.setImageResource(menuResIds[i]);
				addView(imageView);
				LayoutParams params = (FrameLayout.LayoutParams)imageView.getLayoutParams();
				params.width = LayoutParams.WRAP_CONTENT;
				params.height = LayoutParams.WRAP_CONTENT;			
				params.leftMargin = mWIDTH / 2 - ((menuResIds.length - i - 1) * width_padding);
				params.bottomMargin = mHEIGHT / 2 - i * height_padding;
				params.gravity = Gravity.LEFT | Gravity.BOTTOM;
				imageView.setLayoutParams(params);						
			}
			break;
		default:
				break;
		}	
		
		mHome.setLayoutParams(mHomeparams);		
	}
	
	private OnClickListener listener = new OnClickListener() {
		
		public void onClick(View v) {
			if (!bMenuShow) {
				startAnimationIn(PathMenuView.this, 300);
			} else {
				startAnimationOut(PathMenuView.this, 300);
			}
			bMenuShow = !bMenuShow;
		}
	};
	
	
	/**
	 * 菜单隐藏动画.
	 * 
	 * @param group
	 * @param duration
	 */
	private void startAnimationIn(ViewGroup group, int duration) {
		for (int i = 1; i < group.getChildCount(); i++) {
			ImageView imageview = (ImageView) group.getChildAt(i);
			imageview.setVisibility(0);
			MarginLayoutParams mlp = (MarginLayoutParams) imageview
					.getLayoutParams();
			
			
			Animation animation = null;
			
			
			switch (position) {
			case LEFT_TOP:
				animation = new TranslateAnimation(0F,-mlp.leftMargin+xOffset,0F,-mlp.topMargin + yOffset);
				break;
			case RIGHT_TOP:
				animation = new TranslateAnimation(mlp.rightMargin - xOffset,0F,-mlp.topMargin + yOffset,0F);
				break;			
			case LEFT_BOTTOM:
				animation = new TranslateAnimation(0F, -mlp.leftMargin+ xOffset, 0F, -yOffset + mlp.bottomMargin);
				break;
				
			case RIGHT_BOTTOM:
				animation = new TranslateAnimation(mlp.rightMargin-xOffset,0F,-yOffset + mlp.bottomMargin, 0F);
				break;
			default:
				break;
			}

			animation.setFillAfter(true);
			animation.setDuration(duration);
			animation.setStartOffset((i * 100) / (-1 + group.getChildCount()));
			animation.setInterpolator(new OvershootInterpolator(2F));
			imageview.startAnimation(animation);

		}
	}
	
	/**
	 * 菜单显示动画.
	 * 
	 * @param group
	 * @param duration
	 */
	private void startAnimationOut(ViewGroup group,int duration){
		for (int i = 1; i < group.getChildCount(); i++) {
			final ImageView imageview = (ImageView) group
					.getChildAt(i);
			MarginLayoutParams mlp = (MarginLayoutParams) imageview.getLayoutParams();
			
			Animation animation = null;
			
			switch (position) {
			case LEFT_TOP:
				animation = new TranslateAnimation(-mlp.leftMargin+xOffset,0F,-mlp.topMargin + yOffset,0F);
				break;
			case RIGHT_TOP:
				animation = new TranslateAnimation(0F,mlp.rightMargin - xOffset,0F,-mlp.topMargin + yOffset);
				break;

			case LEFT_BOTTOM:
				animation = new TranslateAnimation(-mlp.leftMargin+xOffset,0F, -yOffset + mlp.bottomMargin,0F);
				break;

			case RIGHT_BOTTOM:
				animation = new TranslateAnimation(0F,mlp.rightMargin-xOffset, 0F,-yOffset + mlp.bottomMargin);
				break;
			default:
				break;
			}
			
			animation.setFillAfter(true);animation.setDuration(duration);
			animation.setStartOffset(((group.getChildCount()-i) * 100)
					/ (-1 + group.getChildCount()));
			animation.setInterpolator(new AnticipateInterpolator(2F));
			imageview.startAnimation(animation);
		}
	}

}

第四步:PathTestActivity.java以及用到的布局文件main.xml代码如下:

PathTestActivity.java(基本没修改代码)代码如下:

package com.tutor.path;

import android.app.Activity;
import android.os.Bundle;

public class PathTestActivity extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);   
    }
}

main.xml代码如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tutor="http://schemas.android.com/apk/res/com.tutor.path"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <com.tutor.path.PathMenuView
        android:id="@+id/text"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        tutor:position="right_bottom"
         />

</LinearLayout>

运行点击效果如下:


图1:默认是在右下方这里menuResIds定义了五个菜单 图2:点击红色菜单,菜单收回.


下面我们修改main.xml的tutor属性为left_bottom,并且修改PathMenuView.java中的menuResIds.

tutor:position="left_bottom"

效果如下:

图3:自定义在左下角,六个菜单。

好了,今天就讲到这里了,菜单的圆弧不是很圆哈,凑合着学习,我也来无耻下,如果想要源代码的,可以去我的http://www.yqma.net注册一个用户,并且提一个问题,或者回答一个问题,我会把源代码发到你的邮箱里!谢谢!

分享到:
评论

相关推荐

    Android高手进阶教程(二十六)之---Android超仿Path菜单的功能实现!

    在本篇《Android高手进阶教程(二十六)之---Android超仿Path菜单的功能实现!》中,我们将探讨如何在Android应用中实现类似Path应用的菜单功能。Path菜单是一种独特的交互设计,通常以一个中心图标作为触发点,展开多...

    Android高手进阶教程

    ### Android高手进阶教程知识点详解 #### 一、Android常用命令集锦 ##### 1. 环境配置与管理 - **android**: 输入此命令会弹出SDK and AVD Manager界面,允许开发者进行SDK更新及AVD(Android Virtual Device)的...

    android高手进阶教程 完整版 pdf

    ### Android高手进阶教程知识点概览 #### 一、Android常用命令集锦 - **ADB命令**: ADB(Android Debug Bridge)是Android平台下用于调试的工具,它可以帮助开发者进行设备管理、应用安装与卸载等操作。 - `adb ...

    Android高手进阶.doc

    ### Android高手进阶知识点 #### 一、Android命令集锦 **1. Android命令简介** - **作用**:用于管理SDK和AVD。 - **执行方式**:通过设置环境变量或直接进入SDK的tools目录。 **2. 常用命令详解** - **android...

    Android圆形旋转菜单-IT计算机-毕业设计.zip

    这个毕业设计项目就是一个实现这种菜单效果的应用源码示例,旨在帮助学生掌握Android开发技能并进行实践。 首先,我们要理解Android圆形旋转菜单的基本概念。这种菜单通常由一组围绕中心点排列的图标或文字组成,...

    Android应用源码原来PATH的菜单效果如此简单。布局+TranslateAnimation搞定.zip

    布局+TranslateAnimation搞定.zip”揭示了一个利用基本布局和动画实现的PATH菜单效果。在这个压缩包中,包含了一个简单的示例项目,演示了如何使用布局和动画来构建这种效果。 首先,我们要了解Android中的布局...

    android studio 教程

    ### Android Studio 教程知识点详解 #### 一、Android Studio 概述 - **定义**:Android Studio 是一款由 Google 推出的基于 IntelliJ IDEA 的全新 Android 开发环境。它结合了 IntelliJ 的强大功能和 Android 开发...

    android-cocos2d-1

    《Android Cocos2d开发详解:借助项目模板开启游戏之旅》 Cocos2d是一款强大的开源游戏引擎,广泛应用于移动平台的游戏开发,包括Android。在Android平台上,Cocos2d-x是一个C++版本的实现,提供了高效、易用的游戏...

    Android手机程序设计实用教程_PPT.zip

    《Android手机程序设计实用教程》是一份全面介绍Android应用程序开发的教学资料,包含了从基础到进阶的多个关键知识点。这份PPT系列涵盖了Android开发的重要章节,包括: 1. **第1章 Android简介与开发环境**:讲解...

    安卓高端进阶

    ### 安卓高端进阶知识点解析 #### 一、安卓命令行工具的高效利用 针对“安卓高端进阶”这一主题中的描述与内容,本文旨在详细介绍Android开发过程中一系列实用的命令行工具及其应用场景,这对于提高开发效率至关...

    Unity3D教程:Unity3D开发Android游戏1

    ### Unity3D开发Android游戏教程知识点详解 #### 一、Unity3D简介及优势 Unity3D是一款功能强大且易用的游戏开发引擎,支持多种平台的游戏发布,包括但不限于Windows、MacOS、iOS、Android等。它以其直观的操作...

    Android2.3开发环境搭建

    ### Android2.3开发环境搭建详解 在移动互联网迅速发展的时代背景下,Android操作系统以其开放性和灵活性赢得了广大开发者...通过本文的指导,相信每位开发者都能顺利踏上Android应用开发之旅,不断探索、学习和成长。

    Android移动应用开发入门.pdf

    #### 二、创建新的Android项目 - **项目创建流程**:通过File &gt; New &gt; New Project菜单项,按照向导指示完成项目创建。 - **项目结构**:了解项目的文件结构,包括src、res、build.gradle等关键文件夹和文件的作用。...

    android elcipse 源代码 2.1

    标题中的“android eclipse 源代码 2.1”指的是Android 2.1(API级别9)的源代码,这是Android操作系统的一个早期版本,适用于Eclipse集成开发环境(IDE)。这个话题涉及到Android应用开发的基础知识,包括如何在...

    android开发入门

    #### 二、创建第一个Android项目 有了开发环境之后,下一步就是创建一个Android项目,最基础的Hello World项目是一个很好的起点。 ##### 创建项目步骤 1. **启动Eclipse**:确保Eclipse已安装ADT插件,并正确配置...

    android环境开发

    通过以上步骤,可以成功搭建一个完整的Android开发环境,并实现一个简单的Hello World项目。这不仅是学习Android开发的第一步,也为今后深入探索复杂的移动应用开发奠定了坚实的基础。随着技术的发展,建议开发者们...

    android 开发环境搭建详尽

    搭建Android开发环境是每个Android开发者入门的第一步。在这个过程中,我们主要涉及以下几个关键知识点: 1. **JDK安装**:Java Development Kit (JDK) 是Android应用开发的基础,因为Android应用是用Java语言编写...

    Android平台运行调试

    ### Android平台运行调试:在Android模拟器上添加与删除应用 在进行Android开发的过程中,模拟器扮演着不可或缺的角色,尤其对于初次接触Android开发的程序员来说,掌握如何在Android模拟器上添加和删除应用是一项...

Global site tag (gtag.js) - Google Analytics