开始动手之前先来讲一下实现原理,在一个Activity的布局中需要有三部分,一个是左侧菜单的布局,一个是右侧菜单的布局,一个是内容布局。左侧菜单居屏幕左边缘对齐,右侧菜单居屏幕右边缘对齐,然后内容布局占满整个屏幕,并压在了左侧菜单和右侧菜单的上面。当用户手指向右滑动时,将右侧菜单隐藏,左侧菜单显示,然后通过偏移内容布局的位置,就可以让左侧菜单展现出来。同样的道理,当用户手指向左滑动时,将左侧菜单隐藏,右侧菜单显示,也是通过偏移内容布局的位置,就可以让右侧菜单展现出来。

1.新建Android项目,然后新建一个DoubleSlideMenu继承自RelativeLayout,核心类代码:
public class DoubleMenu extends RelativeLayout implements OnTouchListener {
    //滚动和隐藏菜单布局时手指所需要的速度
    private static final int SNAP_VELOCITY=200;
    //未进行任何滑动
    private static final int DO_NOTHING=0;
    //左侧滑动菜单的显示
    private static final int SHOW_LEFT_MENU=1;
    //右侧菜单显示
    private static final int SHOW_RIGHT_MENU=2;
    //左侧菜单隐藏
    private static final int HIDE_LEFT_MENU=3;
    //右侧菜单隐藏
    private static final int HIDE_RIGHT_MENU=4;
    
    //记录滑动的状态
    private int slideState;
    //滑动菜单最小的距离
    private int touchSlop;
    //屏幕宽
    private int screenWidth;
    //按下的横坐标
    private float xDown;
    //按下的纵坐标
    private float yDown;
    //移动的横坐标
    private float xMove;
    //移动的纵坐标
    private float yMove;
    //弹起的横坐标
    private float xUp;
    
    //标志左侧菜单是否显示
    private boolean isLeftMenuVisible;
    //标志右侧菜单是否显示
    private boolean isRightMenuVisible;
    //左侧菜单布局
    private View leftMenuLayout;
    //右侧菜单布局
    private View rightMenuLayout;
    //左侧菜单布局参数
    private MarginLayoutParams leftMenuLayoutParams;
    //右侧菜单布局参数
    private MarginLayoutParams rightMenuLayoutParams;
    //内容页面布局
    private View contentLayout;
    //内容页面布局参数
    private RelativeLayout.LayoutParams contentLayoutParams;
    //标志菜单是否正在滑动
    private boolean isSliding;
    //用于监听滑动事件的View
    private View mBindView;
    //手指的速度
    private VelocityTracker mVelocityTracker;
    
    public DoubleMenu(Context context, AttributeSet attrs) {
        super(context, attrs);
        WindowManager wm=(WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        screenWidth=wm.getDefaultDisplay().getWidth();
        touchSlop=ViewConfiguration.get(context).getScaledTouchSlop();  //触发滚动菜单事件的最小距离
    }
    
    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
        if(changed){
            //获取左侧菜单
            leftMenuLayout=getChildAt(0);
            leftMenuLayoutParams=(MarginLayoutParams) leftMenuLayout.getLayoutParams();
            //获取右侧菜单
            rightMenuLayout=getChildAt(1);
            rightMenuLayoutParams=(MarginLayoutParams) rightMenuLayout.getLayoutParams();
            //获取内容页面
            contentLayout=getChildAt(2);
            contentLayoutParams=(RelativeLayout.LayoutParams) contentLayout.getLayoutParams();
            contentLayoutParams.width=screenWidth;
            contentLayout.setLayoutParams(contentLayoutParams);
        }
    }
    //绑定监听滑动的View
    public void setScrollEvent(View bindView){
        mBindView=bindView;
        mBindView.setOnTouchListener(this);
    }
    
    //判断左侧布局是否显示
    public boolean isLeftMenuVisible(){
        return isLeftMenuVisible;
    }
    //判断右侧布局是否显示
    public boolean isRightMenuVisible(){
        return isRightMenuVisible;
    }
    
    //显示左侧菜单时初始化
    public void initShowLeftState(){
        contentLayoutParams.rightMargin=0;
        contentLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT, 0);
        contentLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
        contentLayout.setLayoutParams(contentLayoutParams);
        leftMenuLayout.setVisibility(View.VISIBLE);
        rightMenuLayout.setVisibility(View.GONE);
    }
    //显示右侧菜单时初始化
    public void initShowRightState(){
        contentLayoutParams.leftMargin=0;
        contentLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, 0);
        contentLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
        contentLayout.setLayoutParams(contentLayoutParams);
        rightMenuLayout.setVisibility(View.VISIBLE);
        leftMenuLayout.setVisibility(View.GONE);
    }
    
    
    //根据手指移动的方向,判断用户滑动意图
    private void checkSlideState(int moveDistanceX,int moveDistanceY){
        if(isLeftMenuVisible){  //如果左侧菜单已经正在显示,判断是否需要关闭
            if(!isSliding&&Math.abs(moveDistanceX)>touchSlop&&moveDistanceX<0){
                isSliding = true;
                slideState=HIDE_LEFT_MENU;
            }
        }
        else if(isRightMenuVisible){
            if(!isSliding&&Math.abs(moveDistanceX)>touchSlop&&moveDistanceX>0){
                isSliding = true;
                slideState=HIDE_RIGHT_MENU;
            }
        }
        else{
            if(!isSliding&&Math.abs(moveDistanceX)>touchSlop&&moveDistanceX>0&&Math.abs(moveDistanceY)<touchSlop){
                isSliding = true;
                slideState=SHOW_LEFT_MENU;
                initShowLeftState();
            }
            else if(!isSliding&&Math.abs(moveDistanceX)>touchSlop&&moveDistanceX<0&&Math.abs(moveDistanceY)<touchSlop){
                isSliding=true;
                slideState=SHOW_RIGHT_MENU;
                initShowRightState();
            }
        }
    }
    
    //在滑动中,检查左侧菜单的边界值
    private void checkLeftMenuBorder(){
        if(contentLayoutParams.rightMargin>0){     
            contentLayoutParams.rightMargin=0;  //隐藏左侧菜单的时刻
        }
        else if(contentLayoutParams.rightMargin<-leftMenuLayoutParams.width){
            contentLayoutParams.rightMargin=-leftMenuLayoutParams.width;  //显示左侧菜单的时刻
        }
    }
    //在滑动过程中检查右侧菜单的边界值
    private void checkRightMenuBorder(){
        if(contentLayoutParams.leftMargin>0){
            contentLayoutParams.leftMargin=0;
        }
        else if(contentLayoutParams.leftMargin<-rightMenuLayoutParams.width){
            contentLayoutParams.leftMargin=-rightMenuLayoutParams.width;
        }
    }
    
    /**
     * 创建VelocityTracker对象,并将触摸事件加入到VelocityTracker当中。
     * 
     * @param event
     *            右侧布局监听控件的滑动事件
     */
    private void createVelocityTracker(MotionEvent event) {
        if (mVelocityTracker == null) {
            mVelocityTracker = VelocityTracker.obtain();
        }
        mVelocityTracker.addMovement(event);
    }
    /**
     * 获取手指在绑定布局上的滑动速度。
     * 
     * @return 滑动速度,以每秒钟移动了多少像素值为单位。
     */
    private int getScrollVelocity() {
        mVelocityTracker.computeCurrentVelocity(1000);
        int velocity = (int) mVelocityTracker.getXVelocity();
        return Math.abs(velocity);
    }
    /**
     * 回收VelocityTracker对象。
     */
    private void recycleVelocityTracker() {
        mVelocityTracker.recycle();
        mVelocityTracker = null;
    }
    
    //判断是否应该将左侧菜单显示出来
    private boolean shouldScrollToLeftMenu(){
        return xUp-xDown>leftMenuLayoutParams.width/2||getScrollVelocity()>SNAP_VELOCITY;
    }
    //判断是否应将右侧菜单显示
    private boolean shouldScrollToRightMenu(){
        return xDown-xUp>rightMenuLayoutParams.width/2||getScrollVelocity()>SNAP_VELOCITY;
    }
    //判断是否应从左侧转到内容页面
    private boolean shouldScrollToContentFromLeft(){
        return xDown-xUp>leftMenuLayoutParams.width/2||getScrollVelocity()>SNAP_VELOCITY;
    }
    //判断是否应从右侧转到内容页面
    private boolean shouldScrollToContentFromRight(){
        return xUp-xDown>rightMenuLayoutParams.width/2|getScrollVelocity()>SNAP_VELOCITY;
    }
    
    //让获得焦点的控件在滑动过程中失去焦点
    private void unFocusBindView(){
        if(mBindView!=null){
            mBindView.setPressed(false);
            mBindView.setFocusable(false);
            mBindView.setFocusableInTouchMode(false);
        }
    }
    
    class LeftMenuScrollTask extends AsyncTask<Integer, Integer, Integer>{
        @Override
        protected Integer doInBackground(Integer... speed) {
            int rightMargin=contentLayoutParams.rightMargin;
            while(true){
                rightMargin=rightMargin+speed[0];
                if(rightMargin>0){  //隐藏
                    rightMargin=0;
                    break;
                }
                if(rightMargin<-leftMenuLayoutParams.width){
                    rightMargin=-leftMenuLayoutParams.width;
                    break;
                }
                publishProgress(rightMargin);
                sleep(15);
            }
            if(speed[0]>0){
                isLeftMenuVisible=false;
            }
            else{
                isLeftMenuVisible=true;
            }
            isSliding=false;
            return rightMargin;
        }
        @Override
        protected void onProgressUpdate(Integer... values) {
            contentLayoutParams.rightMargin=values[0];
            contentLayout.setLayoutParams(contentLayoutParams);
            unFocusBindView();
        }
        @Override
        protected void onPostExecute(Integer result) {
            contentLayoutParams.rightMargin=result;
            contentLayout.setLayoutParams(contentLayoutParams);
        }
    }
    
    class RightMenuScrollTask extends AsyncTask<Integer, Integer, Integer>{
        @Override
        protected Integer doInBackground(Integer... speed) {
            int leftMargin=contentLayoutParams.leftMargin;
            while(true){
                leftMargin=leftMargin+speed[0];
                if(leftMargin>0){
                    leftMargin=0;
                    break;
                }
                if(leftMargin<-rightMenuLayoutParams.width){
                    leftMargin=-rightMenuLayoutParams.width;
                    break;
                }
                publishProgress(leftMargin);
                sleep(20);
            }
            if(speed[0]>0){
                isRightMenuVisible=false;
            }
            else{
                isRightMenuVisible=true;
            }
            isSliding=false;
            return leftMargin;
        }
        @Override
        protected void onProgressUpdate(Integer... values) {
            contentLayoutParams.leftMargin=values[0];
            contentLayout.setLayoutParams(contentLayoutParams);
            unFocusBindView();
        }
        @Override
        protected void onPostExecute(Integer result) {
            contentLayoutParams.leftMargin=result;
            contentLayout.setLayoutParams(contentLayoutParams);
        }
    }
    private void sleep(long millis) {
        try {
            Thread.sleep(millis);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    
    //将界面滚到左侧菜单
    public void scrollToLeftMenu(){
        new LeftMenuScrollTask().execute(-30);
    }
    //将界面滚动到右侧菜单
    public void scrollToRightMenu(){
        new RightMenuScrollTask().execute(-30);
    }
    //将界面从左侧滚到内容
    public void scrollToContentFromLeft(){
        new LeftMenuScrollTask().execute(30);
    }
    //将界面从右侧滚到内容
    public void scrollToContentFromRight(){
        new RightMenuScrollTask().execute(30);
    }
    
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        createVelocityTracker(event);
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            xDown=event.getRawX();
            yDown=event.getRawY();
            slideState=DO_NOTHING;
            break;
        case MotionEvent.ACTION_MOVE:{
            xMove=event.getRawX();
            yMove=event.getRawY();
            int moveDistanceX=(int)(xMove-xDown);
            int moveDistanceY=(int)(yMove-yDown);
            checkSlideState(moveDistanceX, moveDistanceY);
            switch (slideState) {
            case SHOW_LEFT_MENU:
                contentLayoutParams.rightMargin=-moveDistanceX;
                checkLeftMenuBorder();
                contentLayout.setLayoutParams(contentLayoutParams);
                break;
            case HIDE_LEFT_MENU:
                contentLayoutParams.rightMargin=-leftMenuLayoutParams.width-moveDistanceX;
                checkLeftMenuBorder();
                contentLayout.setLayoutParams(contentLayoutParams);
                break;
            case SHOW_RIGHT_MENU:
                contentLayoutParams.leftMargin=moveDistanceX;
                checkRightMenuBorder();
                contentLayout.setLayoutParams(contentLayoutParams);
                break;
            case HIDE_RIGHT_MENU:
                contentLayoutParams.leftMargin=-rightMenuLayoutParams.width+moveDistanceX;
                checkRightMenuBorder();
                contentLayout.setLayoutParams(contentLayoutParams);
                break;
              }
            break;
            }
        case MotionEvent.ACTION_UP:
            xUp=event.getRawX();
            int upDistanceX=(int)(xUp-xDown);
            if(isSliding){
                switch (slideState) {
                case SHOW_LEFT_MENU:
                    if(shouldScrollToLeftMenu()){
                        scrollToLeftMenu();
                    }
                    else{
                        scrollToContentFromLeft();
                    }
                    break;
                case HIDE_LEFT_MENU:
                    if(shouldScrollToContentFromLeft()){
                        scrollToContentFromLeft();
                    }
                    else{
                        scrollToLeftMenu();
                    }
                    break;
                case SHOW_RIGHT_MENU:
                    if(shouldScrollToRightMenu()){
                        scrollToRightMenu();
                    }
                    else{
                        scrollToContentFromRight();
                    }
                    break;
                case HIDE_RIGHT_MENU:
                    if(shouldScrollToContentFromRight()){
                        scrollToContentFromRight();
                    }
                    else{
                        scrollToRightMenu();
                    }
                default:
                    break;
                }
            }
            else if(upDistanceX<touchSlop&&isLeftMenuVisible){
                scrollToContentFromLeft();
            }
            else if(upDistanceX<touchSlop&&isRightMenuVisible){
                scrollToContentFromRight();
            }
            recycleVelocityTracker();
            break;
        }
        
        if(v.isClickable()){   //这里要求控件必须是clickable的.
            if(isSliding){
                unFocusBindView();  //正在滑动时取消控件焦点
                return true;
            }
            if(isLeftMenuVisible||isRightMenuVisible){
                return true;//当左菜单或右菜单显示时,取消触摸事件
            }
            return false;
        }
        return true;
    }
}
首先在onLayout()方法中分别获取到左侧菜单、右侧菜单和内容布局的参数,并将内容布局的宽度重定义成屏幕的宽度,这样就可以保证内容布局既能覆盖住下面的菜单布局,还能偏移出屏幕。然后在onTouch()方法中监听触屏事件,以判断用户手势的意图。这里事先定义好了几种滑动状态,DO_NOTHING表示没有进行任何滑动,SHOW_LEFT_MENU表示用户想要滑出左侧菜单,SHOW_RIGHT_MENU表示用户想要滑出右侧菜单,HIDE_LEFT_MENU表示用户想要隐藏左侧菜单,HIDE_RIGHT_MENU表示用户想要隐藏右侧菜单,在checkSlideState()方法中判断出用户到底是想进行哪一种滑动操作,并给slideState变量赋值,然后根据slideState的值决定如何偏移内容布局。接着当用户手指离开屏幕时,会根据当前的滑动距离,决定后续的滚动方向,通过LeftMenuScrollTask和RightMenuScrollTask来完成完整的滑动过程。另外在滑动的过程,内容布局上的事件会被屏蔽掉,主要是通过一系列的return操作实现的.
2.打开activity_main.xml
<com.example.doubleslidemenu.DoubleMenu 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"
    android:id="@+id/double_slideMenu"
    tools:context=".MainActivity" >
    <RelativeLayout 
        android:layout_width="270dp"
        android:layout_height="fill_parent"
        android:id="@+id/left_menu"
        android:layout_alignParentLeft="true"
        android:background="#00ccff"
        android:visibility="invisible" 
        >
                <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:text="This is left menu"
            android:textColor="#000000"
            android:textSize="28sp" />
    </RelativeLayout>
    
        <RelativeLayout
        android:id="@+id/right_menu"
        android:layout_width="270dip"
        android:layout_height="fill_parent"
        android:layout_alignParentRight="true"
        android:background="#00ffcc"
        android:visibility="invisible" >
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:text="This is right menu"
            android:textColor="#000000"
            android:textSize="28sp" />
    </RelativeLayout>
     <LinearLayout
        android:id="@+id/content"
        android:layout_width="320dip"
        android:layout_height="fill_parent"
        android:orientation="vertical"
        android:background="#e9e9e9" >
        <RelativeLayout 
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            >
            <Button 
                android:id="@+id/show_left_button"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentLeft="true"
                android:text="show left"
                />
            <Button 
                android:id="@+id/show_right_button"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentRight="true"
                android:text="show right"
                />
        </RelativeLayout>
        <ListView
            android:id="@+id/contentList"
            android:layout_width="fill_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            android:scrollbars="none"
            android:cacheColorHint="#00000000" >
        </ListView>
    </LinearLayout>
</com.example.doubleslidemenu.DoubleMenu>
3.打开MainActivity.java
public class MainActivity extends Activity {
    /**
     * 双向滑动菜单布局
     */
    private DoubleMenu bidirSldingLayout;
    /**
     * 在内容布局上显示的ListView
     */
    private ListView contentList;
    /**
     * ListView的适配器
     */
    private ArrayAdapter<String> contentListAdapter;
    /**
     * 用于填充contentListAdapter的数据源。
     */
    private String[] contentItems = { "Content Item 1", "Content Item 2", "Content Item 3",
            "Content Item 4", "Content Item 5", "Content Item 6", "Content Item 7",
            "Content Item 8", "Content Item 9", "Content Item 10", "Content Item 11",
            "Content Item 12", "Content Item 13", "Content Item 14", "Content Item 15",
            "Content Item 16" };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        bidirSldingLayout = (DoubleMenu) findViewById(R.id.double_slideMenu);
        Button showLeftButton = (Button) findViewById(R.id.show_left_button);
        Button showRightButton = (Button) findViewById(R.id.show_right_button);
        contentList = (ListView) findViewById(R.id.contentList);
        contentListAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1,
                contentItems);
        contentList.setAdapter(contentListAdapter);
        bidirSldingLayout.setScrollEvent(contentList);
        showLeftButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                if (bidirSldingLayout.isLeftMenuVisible()) {
                    bidirSldingLayout.scrollToContentFromLeft();
                } else {
                    bidirSldingLayout.initShowLeftState();
                    bidirSldingLayout.scrollToLeftMenu();
                }
            }
        });
        showRightButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                if (bidirSldingLayout.isRightMenuVisible()) {
                    bidirSldingLayout.scrollToContentFromRight();
                } else {
                    bidirSldingLayout.initShowRightState();
                    bidirSldingLayout.scrollToRightMenu();
                }
            }
        });
    }
}
至此,可以双向滑动的SlideMenu就完成了.


android之SlideMenu双向滑动的更多相关文章

  1. Android双向滑动菜单完全解析,教你如何一分钟实现双向滑动特效

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/9671609 记得在很早之前,我写了一篇关于Android滑动菜单的文章,其中有一个 ...

  2. Android 侧滑(双向滑动菜单)效果

    下面看看我们如何使用它,达到我们想要的效果 public class MainActivity extends Activity { /** * 双向滑动菜单布局 */ private SliderM ...

  3. 【转】Android双向滑动菜单完全解析,教你如何一分钟实现双向滑动特效

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/9671609 记得在很早之前,我写了一篇关于Android滑动菜单的文章,其中有一个 ...

  4. 超酷的Android 侧滑(双向滑动菜单)效果

    下面看看我们如何使用它,达到我们想要的效果 public class MainActivity extends Activity { /** * 双向滑动菜单布局 */ private SliderM ...

  5. Android ScrollView监听滑动到顶部和底部的两种方式(你可能不知道的细节)

    Android ScrollView监听滑动到顶部和底部,虽然网上很多资料都有说,但是不全,而且有些细节没说清楚 使用场景: 1. 做一些复杂动画的时候,需要动态判断当前的ScrollView是否滚动 ...

  6. 仿优酷Android客户端图片左右滑动(自动滑动)

    最终效果: 页面布局main.xml: <?xml version="1.0" encoding="utf-8"?> <LinearLayou ...

  7. Android判断Touch为滑动事件还是操作控件

    Android判断Touch为滑动事件还是操作控件 因为在项目中要判断WebView是否处于滚动状态,但它不像ListView有onScrollStateChanged方法来监听,要实现就得手动监听它 ...

  8. android中无限循环滑动的gallery实例

    android中无限循环滑动的gallery实例 1.点击图片有变暗的效果,使用imageview.setAlpha(),并且添加ontouchListener public void init() ...

  9. Android开发之手势滑动(滑动手势监听)详解

    Android开发之手势滑动(滑动手势监听)详解 在Android应用中,经常需要手势滑动操作,比如上下滑动,或左右方向滑动,处理手势滑动通常有两种方法:一种是单独实现setOnTouchListen ...

随机推荐

  1. android ndk中使用gprof

    1.下载gprof支持库 下载地址: http://code.google.com/p/android-ndk-profiler/ 2.代码上的修改添加 在初始化时: monstartup(" ...

  2. 统计函数运行时间-CPU端

    C/C++中的计时函数是clock(),而与其相关的数据类型是clock_t.在MSDN中,查得对clock函数定义如下:  clock_t clock( void ); 这个函数返回从“开启这个程序 ...

  3. 【PC-x86-x64】JDK 32bit与64bit的区别及x64 PC的发展历程【转】

    一次偶然分析的机会: 在进行Minecraft也就是所谓的我的世界游戏的时候,在对局域网进行开放的时候,我的是64bit的JDK,而我同学的是32bit的JDK,所以在进行局域网链接的时候就会出现In ...

  4. Java中的逻辑运算符短路效应

    在Java中逻辑运算符&& 和 ||,它们都存在短路效应. 对于a && b,只有当a和b同时为true时,整个表达式才为true(在java中,首先运算表达式a,如果 ...

  5. 通过eclipse启动tomcat设置JAVA_OPTS失败的解决方案

    clipse中配置tomcat方法: Window-->Preference-->Server-->Runtime Environment-->add-->Apache ...

  6. Mysql url参数浅析

    驱动包用的是mysql-connector-java-8.0.11.jar 新版的驱动类改成了com.mysql.cj.jdbc.Driver //北京时间东八区 serverTimezone=GMT ...

  7. iconv for linux(c)

    // code_convert("gb2312","utf-8",inbuf,outbuf,outlen);static int code_convert(co ...

  8. 2018/7/16 YMOI模拟 NOIP2013D2T3华容道

    题目描述 Description 小 B 最近迷上了华容道,可是他总是要花很长的时间才能完成一次.于是,他想到用编程来完成华容道:给定一种局面,华容道是否根本就无法完成,如果能完成,最少需要多少时间. ...

  9. 云计算之KVM虚拟化实战

    1 基础环境规划 1.1 主机环境规划 系统版本 主机名 IP地址 内存 磁盘 CentOS6.9 kvm-node1 10.0.0.200 2G 20G CentOS6.9 kvm-node2 10 ...

  10. python——“/”运算符和“//”运算符的区别

    首先先看单斜杆的用法:举几个例子 >>> print(5/3),type(5/3)1.6666666666666667(None, <class 'float'>) &g ...