从网上学习了hyman大神的卫星菜单实现,自己特意亲自又写了一编代码,对自定义ViewGroup的理解又深入了一点。我坚信只有自己写出来的知识才会有更加好的的掌握。因此也在自己的博客中将这个卫星菜单的案例给实现了。废话不多说,直接进入正题吧。

该案例的完整代码以及相关的图片素材下载链接如下:

http://download.csdn.net/detail/fuyk12/9233573

一、效果展示

首先上一张效果图,如下:

这是在模拟器上的运行效果,有点卡顿。在真机上,是会很流畅,而且动画效果显示的会更清晰。

效果说明:红色按钮是菜单按钮,点击它,会弹出菜单选项。菜单选项会像一个四分之一圆一样围绕在菜单按钮周围。而菜单的弹出采用了动画效果。如果点击菜单,则同时菜单消失且会弹出一个提示框。更具体的细节效果,看上面的效果图应该很明白了。

所用的知识:(1)自定义ViewGroup。整个菜单的绘制就是一个自定义的ViewGroup。所以这其中要清楚理解view的绘制流程,还要掌握住自定义属性等知识。

(2)android中的常用的补间动画,例如菜单的弹出就是平移动画和旋转动画的结合。而点击菜单时,是缩放动画和透明动画的实现。

难点:我们android的补间动画实际上视觉上的一种错觉,比如一个按钮你看到它平移了,实际上它只是android在另外一个地方重新绘制了,并不是原来的按钮,原来的按钮还      在初始位置,因此你点击它是没有效果的。为了解决这个问题,android推出了属性动画。但是属性动画向下兼容性不是很好。为了解决这样子的难点,我们依旧采用补                 间 动画,但是在逻辑上做了一个巧妙的处理。具体的怎么处理,等到了这一步,再详细说明。

实现这个案例的思路:我们打算分这么几步来实现这个卫星菜单。

(1)首先将各个菜单以及按钮给完整的绘制出来。即完成自定义ViewGroup。

(2)完成菜单的弹出动画。

(3)完成菜单的点击动画。

(4)完成菜单点击事件的逻辑,比如弹出提示框。

因此这是一个实战的案例,不是基础知识的讲解。需要读者具有相关的知识后才能很好的阅读。那么本篇文章就来实现第一步,即将整个菜单给绘制出来。

二、自定义ViewGruop完成菜单绘制

从菜单按钮以及菜单选项,都是一个自定义的ViewGroup。从效果图上可以看到,菜单选项以一个四分之一圆的方式围绕菜单。因此这个自定义的ViewGroup需要具有圆的半径这个属性。效果图中只展示了按钮位于右下角的情况,其实那个加号按钮完全可以放在左上,左下,右上。因此,我们给这个自定义的ViewGroup再添加一个属性,为位置属性。这样子一来,用户就可以放在四个角的其他位置了。这些分析,其实就是自定义属性里面的内容。表现在代码中,如下所示。

新建项目,然后再res下的values文件下新建attrs.xml文件,其中的代码如下:

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

从代码中,可以看到我们定义了一个属性集合“ArcMenu",其中有两个属性"position"和"radius”,对应于自定义ViewGruop的位置和需要的半径。其实ArcMenu就是我们自定义ViewGroup的名称。我们先将其建立出来。

新建类ArcMenu继承自ViewGroup,代码如下:

 package com.example.menu;

 import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;
import android.view.ViewGroup; public class ArcMenu extends ViewGroup { public ArcMenu(Context context) {
this(context,null);
}
public ArcMenu(Context context, AttributeSet attrs) {
this(context,attrs,0);
}
public ArcMenu(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle); } }

代码很简单,我们没有做任何操作。下面要做的就是把这个自定义的ViewGroup添加到布局中,并向里面添加控件,即我们的菜单。

修改activity_main.xml中的代码,如下:

 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:kun="http://schemas.android.com/apk/res/com.example.menu"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" > <com.example.menu.ArcMenu
android:layout_width="match_parent"
android:layout_height="match_parent"
kun:position="right_bottom"
kun:radius="200dp">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/composer_button" >
<ImageView
android:id="@+id/id_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:src="@drawable/composer_icn_plus"/>
</RelativeLayout>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/composer_camera"
android:tag="Camera"/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/composer_music"
android:tag="Music"/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/composer_place"
android:tag="Place"/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/composer_sleep"
android:tag="Sleep"/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/composer_thought"
android:tag="Thought"/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/composer_with"
android:tag="People"/> </com.example.menu.ArcMenu> </LinearLayout>

大体是一个线性布局。然后在里面放入了自定义的ViewGroup,即ArcMenu。注意在第11行和第12行我们为ArcMenu指定了位置为右下,半径为200dp。你可以完全指定不同的位置和大小。而且我们在ArcMenu里面放入了好几个ImageView,这些ImageView就是我们的菜单,至于图片资源可以单击文章开头的链接下载。ImageView的个数,你完全可以自己来定,在这里我们放入了6个,,也就是有6个菜单选项。并且为每一个ImageView都指定了tag。这有什么用呢,先不用管它。你或许会有疑问,这些ImageView是怎么摆放的啊?所以接下来,赶快修改ArcMenu中的代码,将这个控件都摆放好。

ArcMenu中的代码先贴出来吧,然后再解释,如下:

 package com.example.menu;

 import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;
import android.view.ViewGroup; public class ArcMenu extends ViewGroup implements OnClickListener {
/**
* 菜单按钮
*/
private View mCBMenu;
/**
* 菜单的位置,为枚举类型
* @author fuly1314
*
*/
private enum Position
{
LEFT_TOP,LEFT_BOTTOM,RIGHT_TOP,RIGHT_BOTTOM
}
/**
* 菜单的状态
* @author fuly1314
*
*/
private enum Status
{
OPEN,CLOSE
}
/**
* 菜单为当前位置,默认为RIGHT_BOTTOM,在后面我们可以获取到
*/
private Position mPosition = Position.RIGHT_BOTTOM;
/**
* 菜单的当前状态,默认为开启
*/
private Status mCurStatus = Status.OPEN; /**
* 菜单的半径,默认为120dp
*/
private int mRadius = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 150,
getResources().getDisplayMetrics()); public ArcMenu(Context context) {
this(context,null);
}
public ArcMenu(Context context, AttributeSet attrs) {
this(context,attrs,0);
}
public ArcMenu(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle); TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.ArcMenu, defStyle, 0);
//获取到菜单设置的位置
int position = ta.getInt(R.styleable.ArcMenu_position, 3); switch(position){
case 0:
mPosition = Position.LEFT_TOP;
break;
case 1:
mPosition = Position.LEFT_BOTTOM;
break;
case 2:
mPosition = Position.RIGHT_TOP;
break;
case 3:
mPosition = Position.RIGHT_BOTTOM;
break;
} //获取到菜单的半径
mRadius = (int) ta.getDimension(R.styleable.ArcMenu_radius,
TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 120,
getResources().getDisplayMetrics()));
ta.recycle(); } /**
* 测量各个子View的大小
*/
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
int count = getChildCount();//获取子view的数量 for(int i=0;i<count;i++)
{
//测量子view的大小
measureChild(getChildAt(i), widthMeasureSpec, heightMeasureSpec);
} super.onMeasure(widthMeasureSpec, heightMeasureSpec);
} /**
* 摆放各个子view的位置
*/
protected void onLayout(boolean changed, int l, int t, int r, int b) { if(changed)//如果发生了改变,就重新布局
{
layoutMainMenu();//菜单按钮的布局 } }
/**
* 菜单按钮的布局
*/
private void layoutMainMenu() { mCBMenu = getChildAt(0);//获得主菜单按钮 mCBMenu.setOnClickListener(this); int left=0;
int top=0; switch(mPosition)
{
case LEFT_TOP:
left = 0;
top = 0;
break;
case LEFT_BOTTOM:
left = 0;
top = getMeasuredHeight() - mCBMenu.getMeasuredHeight();
break;
case RIGHT_TOP:
left = getMeasuredWidth() - mCBMenu.getMeasuredWidth();
top = 0;
break;
case RIGHT_BOTTOM:
left = getMeasuredWidth() - mCBMenu.getMeasuredWidth();
top = getMeasuredHeight() - mCBMenu.getMeasuredHeight();
break;
} mCBMenu.layout(left, top, left+mCBMenu.getMeasuredWidth(), top+mCBMenu.getMeasuredHeight());
}
/**
* 菜单按钮的点击事件
* @param v
*/
public void onClick(View v) {
//为菜单按钮设置点击动画
RotateAnimation rAnimation = new RotateAnimation(0f, 720f, Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f); rAnimation.setDuration(300); rAnimation.setFillAfter(true); v.startAnimation(rAnimation); } }

代码有点长,但是很简单。首先是成员变量,我们需要知道当前菜单按钮的位置,是放在右下了还是左上,还需要当前菜单的状态,菜单已经折叠了还是已经打开了,更需要知道半径,这样才好设定菜单的位置啊,因此才有了这些成员变量。再然后就是在构造方法中获取我们在布局中的给ArcMenu设定的位置属性和半径属性,从而将成员变量初始化。

接着在onMeasure方法,对放进ArcMenu中的每个子view进行测量,这样子就知道了每一个子view的大小,代码很简单,measureChild一下即可。然后就可以执行onLayout方法来摆放每一个子view的位置了。这里我们先摆放菜单按钮的位置,因为它比较简单。菜单,即布局中的ImageView先不管。然后又给菜单按钮添加了点击事件,即点击的时候,要它自身旋转一下。好了,代码很简单,看注释很容易理解。我们运行下,看看效果。如下:

右下角有个红色的按钮,点击还有旋转(由于贴出来的不是动态图,因此旋转效果小伙伴可以在自己的实验中看到)。好了,菜单按钮我们布局算是成功了。下面就开始布局那些菜单吧。

关于这些菜单,即这些ImageView的布局,牵涉到简单的数学知识。下面有一张我绘制的图片,简单来说明一下。

假设菜单按钮放在左上角,围绕它的菜单如上图,红色的圈圈为代表。其中线段AB就是我们所设定的半径的长度,用radius来表示。现在我们如果想求A点的坐标(其中A是对应菜单的顶点坐标),根据简单的数学知识,就会得到如下结果:

x = radius * cos(a)
y = radius * sin(a)

那么同样的道理,对于第 i 个菜单,它的顶点坐标就如下可求:

x = radius * cos(a*i)
y = radius * sin(a*i)

好了,现在回到我们的程序中来。要知道,在代码中,你要注意以下问题:

(1)遍历的子view的坐标是从0开始的。
(2)遍历的子view包括菜单按钮,因为我们要出去它。
(3)a的值应该是90除以菜单个数

注意到上面的问题,再结合我们前面分析到的数学知识,很容易可以得到每一个子view的顶点坐标了,代码如下:

 for(int i=0;i<count-1;i++)
{
View childView = getChildAt(i+1);//注意这里过滤掉菜单按钮,只要菜单选项view int left = (int) (mRadius*Math.cos(Math.PI/2/(count-2)*i));
int top = (int) (mRadius*Math.sin(Math.PI/2/(count-2)*i)); switch(mPosition)
{ case LEFT_TOP:
break;
case LEFT_BOTTOM:
top = getMeasuredHeight() - top-childView.getMeasuredHeight();
break;
case RIGHT_TOP:
left = getMeasuredWidth() - left-childView.getMeasuredWidth();
break;
case RIGHT_BOTTOM:
left = getMeasuredWidth() - left-childView.getMeasuredWidth();
top = getMeasuredHeight() - top-childView.getMeasuredHeight();
break;
}
}

怎么会多出switch语句呢?这是因为比如菜单按钮位于右下,则顶点坐标的高度应该是整体高度去掉控件本身的高度以及顶点高度。如下图所示:

swtich的其他语句相信小伙伴仔细想想应该很快就会明白为什么这么计算了吧。道理是一样的。拿个本子,用笔画画就知道了

讲了那么多,我们就将上面我们所讲的整合到代码中。那么修改ArcMenu,摆放我们的菜单吧!代码如下:

 package com.example.menu;

 import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;
import android.view.ViewGroup; public class ArcMenu extends ViewGroup implements OnClickListener{
/**
* 菜单按钮
*/
private View mCBMenu;
/**
* 菜单的位置,为枚举类型
* @author fuly1314
*
*/
private enum Position
{
LEFT_TOP,LEFT_BOTTOM,RIGHT_TOP,RIGHT_BOTTOM
}
/**
* 菜单的状态
* @author fuly1314
*
*/
private enum Status
{
OPEN,CLOSE
}
/**
* 菜单为当前位置,默认为RIGHT_BOTTOM,在后面我们可以获取到
*/
private Position mPosition = Position.RIGHT_BOTTOM;
/**
* 菜单的当前状态,默认为开启
*/
private Status mCurStatus = Status.OPEN; /**
* 菜单的半径,默认为120dp
*/
private int mRadius = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 150,
getResources().getDisplayMetrics()); public ArcMenu(Context context) {
this(context,null);
}
public ArcMenu(Context context, AttributeSet attrs) {
this(context,attrs,0);
}
public ArcMenu(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle); TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.ArcMenu, defStyle, 0);
//获取到菜单设置的位置
int position = ta.getInt(R.styleable.ArcMenu_position, 3); switch(position){
case 0:
mPosition = Position.LEFT_TOP;
break;
case 1:
mPosition = Position.LEFT_BOTTOM;
break;
case 2:
mPosition = Position.RIGHT_TOP;
break;
case 3:
mPosition = Position.RIGHT_BOTTOM;
break;
} //获取到菜单的半径
mRadius = (int) ta.getDimension(R.styleable.ArcMenu_radius,
TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 120,
getResources().getDisplayMetrics()));
ta.recycle(); } /**
* 测量各个子View的大小
*/
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
int count = getChildCount();//获取子view的数量 for(int i=0;i<count;i++)
{
//测量子view的大小
measureChild(getChildAt(i), widthMeasureSpec, heightMeasureSpec);
} super.onMeasure(widthMeasureSpec, heightMeasureSpec);
} /**
* 摆放各个子view的位置
*/
protected void onLayout(boolean changed, int l, int t, int r, int b) { if(changed)//如果发生了改变,就重新布局
{
layoutMainMenu();//菜单按钮的布局
/**
* 下面的代码为菜单的布局
*/
int count = getChildCount(); 120 for(int i=0;i<count-1;i++)
121 {
122 View childView = getChildAt(i+1);//注意这里过滤掉菜单按钮,只要菜单选项view
123
124 int left = (int) (mRadius*Math.cos(Math.PI/2/(count-2)*i));
125 int top = (int) (mRadius*Math.sin(Math.PI/2/(count-2)*i));
126
127 switch(mPosition)
128 {
129
130 case LEFT_TOP:
131 break;
132 case LEFT_BOTTOM:
133 top = getMeasuredHeight() - top-childView.getMeasuredHeight();
134 break;
135 case RIGHT_TOP:
136 left = getMeasuredWidth() - left-childView.getMeasuredWidth();
137 break;
138 case RIGHT_BOTTOM:
139 left = getMeasuredWidth() - left-childView.getMeasuredWidth();
140 top = getMeasuredHeight() - top-childView.getMeasuredHeight();
141 break;
142 }
143
144 childView.layout(left, top, left+childView.getMeasuredWidth(),
145 top+childView.getMeasuredHeight());
146 }
147 }
148 }
/**
* 菜单按钮的布局
*/
private void layoutMainMenu() { mCBMenu = getChildAt(0);//获得主菜单按钮 mCBMenu.setOnClickListener(this); int left=0;
int top=0; switch(mPosition)
{
case LEFT_TOP:
left = 0;
top = 0;
break;
case LEFT_BOTTOM:
left = 0;
top = getMeasuredHeight() - mCBMenu.getMeasuredHeight();
break;
case RIGHT_TOP:
left = getMeasuredWidth() - mCBMenu.getMeasuredWidth();
top = 0;
break;
case RIGHT_BOTTOM:
left = getMeasuredWidth() - mCBMenu.getMeasuredWidth();
top = getMeasuredHeight() - mCBMenu.getMeasuredHeight();
break;
} mCBMenu.layout(left, top, left+mCBMenu.getMeasuredWidth(), top+mCBMenu.getMeasuredHeight());
}
/**
* 菜单按钮的点击事件
* @param v
*/
public void onClick(View v) {
//为菜单按钮设置点击动画
RotateAnimation rAnimation = new RotateAnimation(0f, 720f, Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f); rAnimation.setDuration(300); rAnimation.setFillAfter(true); v.startAnimation(rAnimation); } }

注意红色部分的代码,这样子我们就把每一个菜单摆放到位了。那么是不是呢?快运行一下程序,看看效果。如下:

效果还不错哈。至此,ArcMenu每一个子view都绘制出来了。我们下面要出来的就是菜单的动画效果了。保存好现在的代码,快快进入下一节中吧。《实现菜单弹出动画》

(一)自定义ViewGroup绘制出菜单的更多相关文章

  1. android自定义viewgroup初步之一----抽屉菜单

    转载请注明出处 http://blog.csdn.net/wingichoy/article/details/47832151 几天前在慕课网上看到鸿洋老师的 自定义卫星菜单,感觉很有意思,于是看完视 ...

  2. Android 自定义ViewGroup,实现侧方位滑动菜单

    侧方位滑动菜单 1.现在adnroid流行的应用当中很多都是用的侧方位滑动菜单如图:

  3. 自定义ViewGroup基础巩固2---onMeasure()学习及综合实现圆形菜单

    上次对自定义ViewGroup中的onLayout()方法进行了基础巩固[http://www.cnblogs.com/webor2006/p/7507284.html],对于熟知自定义ViewGro ...

  4. android 自定义ViewGroup和对view进行切图动画实现滑动菜单SlidingMenu

    示意图就不展示了,和上一节的一样,滑动菜单SlidingMenu效果如何大家都比较熟悉,在这里我简单说明一下用自定义ViewGroup来实现. 实现方法:我们自定义一个ViewGroup实现左右滑动, ...

  5. android 自定义ViewGroup和对view进行切图动画实现滑动菜单SlidingMenu[转]

    http://blog.csdn.net/jj120522/article/details/8095852 示意图就不展示了,和上一节的一样,滑动菜单SlidingMenu效果如何大家都比较熟悉,在这 ...

  6. Android定位&地图&导航——基于百度地图,实现自定义图标绘制并点击时弹出泡泡

    一.问题描述 上一次我们使用百度地图实现基本的定位功能,接下来我们继续实现搜索和定位,并使用LocationOverlay绘制定位位置,同时展示如何使用自定义图标绘制并点击时弹出泡泡 如图所示: 二. ...

  7. 用PopupWindow实现弹出菜单(弹出的菜单采用自定义布局)

         用PopupWindow实现弹出菜单是一个比较好的方式.当然我们还有一个类PopupMenu也能实现弹出菜单,但那个太过于局限了,所以不是很推荐. 这个实例的效果是这样的:点击按钮后,一个菜 ...

  8. PopupWindow(2)简单示例-自定义弹出菜单

    本示例,用 popupWindow 自定义弹出菜单 public class CustomActionProvider extends ActionProvider implements OnMenu ...

  9. WPF自定义Popup和弹出菜单

    Popup: <StackPanel Grid.Column="0" Grid.Row="6" Orientation="Horizontal& ...

随机推荐

  1. css选择器星号(*)

    1.星号(*)选择器的优先级 css的(*)选择器,也是通用选择器,对所有的页面元素(html,title,style,body,div,p……)应用样式,级别最低 在选择器的级别中:在元素名< ...

  2. Codeforces 639B——Bear and Forgotten Tree 3——————【构造、树】

    Bear and Forgotten Tree 3 time limit per test 2 seconds memory limit per test 256 megabytes input st ...

  3. Oracle PL/SQL Developer 上传下载Excel

    接到需求,Oracle数据库对Excel数据进行上传和下载,百度后没有很全的方案,整理搜到的资料,以备不时之需. 一.下载Oracle数据到Excel中. 下载数据到Excel在MSSql中很简单,直 ...

  4. spring的事务管理配置

    spring有两种事务配置器,可以使用spring的jdbc事务管理器,也可以使用对hibernate的事务管理器 第一种 使用Spring JDBC或IBatis进行事务配置(配置文件方式): &l ...

  5. Effective C++ .05 一些不自动生成copy assigment操作的情况

    主要讲了 1. 一般情况下编译器会为类创建默认的构造函数,拷贝构造函数和copy assignment函数 2. 执行默认的拷贝构造/copy assignment函数时,如果成员有自己的拷贝构造/c ...

  6. JavaScript里面的居民们3-去除空格和重复

    如代码,分别实现 diyTrim 及 removeRepetition 函数,并跑通代码中的测试用例. <!DOCTYPE html> <html> <head> ...

  7. Bzoj1492: [NOI2007]货币兑换Cash(不单调的斜率优化)

    题面 传送门 Sol 题目都说了 必然存在一种最优的买卖方案满足: 每次买进操作使用完所有的人民币: 每次卖出操作卖出所有的金券. 设\(f[i]\)表示第\(i\)天可以有的最大钱数 枚举\(j&l ...

  8. element中文件上传

    vue+element 文件操作 作者:一粒尘土 时间:2019-3-17 注:以下操作针对 vue-cli 目录 使用 组件常用参数 组件常用方法 上传文件 上传文件格式限制 回显文件 下载文件 删 ...

  9. Java中线程的实现

    在Java中要想实现多线程代码有两种方法,一种是继承 Thread 类,另一种就是实现 Runnable 接口 一.继承 Thread 类 Thread 类是在 java.lang 包中定义的,一个类 ...

  10. Java从入门到精通——数据库篇Mongo DB 安装启动及配置详解

    一.概述     Mongo DB 下载下来以后我们应该如何去安装启动和配置才能使用Mongo DB,本篇博客就给大家讲述一下Mongo DB的安装启动及配置详解. 二.安装 1.下载Mongo DB ...