摘要: 转载请注明出处:http://blog.csdn.net/allen315410/article/details/42914501 概述        今天这篇博客将记录一些关于DrawerLayout的基本用法,我想关于DrawerLayout的用法也许有不少不够了解,这也是比较正常的事情...

转载请注明出处:http://blog.csdn.net/allen315410/article/details/42914501

概述

今天这篇博客将记录一些关于DrawerLayout的基本用法,我想关于DrawerLayout的用法也许有不少不够了解,这也是比较正常的事情,因为DrawerLayout作为Android组件是Google后来在android中添加的,在android.support.v4包下。那么,DrawerLayout是一个怎么的组件呢?我们知道,当我们使用Android上各类App的时候,是不是注意过App主页上通常有一个“侧滑菜单”?关于侧滑菜单的实现,我在前面博客里有一些介绍,想多些了解的朋友请移步:

Android自定义控件——侧滑菜单

Android自定义控件——开源组件SlidingMenu的项目集成

这里用“网易新闻”客户端v4.4的截图来说明一下,这个DrawerLayout抽屉式布局是什么样子的。

   

好,大家已经看到了,网易新闻客户端效果很明显,当我们手指在屏幕左侧向右滑动时候,就会有一个抽屉式的菜单从左边弹出,并且是“悬浮”在主界面之上的,合理的利用了设备上有限的空间,同样手指在屏幕右侧向左滑动也会出现一个向左弹出的抽屉式菜单,用户体验效果还是不错的,在DrawerLayout出现之前,我们需要做侧滑菜单时,不得不自己实现一个或者使用Github上的开源的项目SlidingMenu,也许是Google也看到了SlidingMenu的强大之处,于是在Android的后期版本中添加了DrawerLayout来实现SlidingMenu同样功能的组件,而且为了兼容早期版本,将其添加在android,support.v4包下。

关于DrawerLayout的Training:http://developer.android.com/training/implementing-navigation/nav-drawer.html

关于DrawerLayout的API:http://developer.android.com/reference/android/support/v4/widget/DrawerLayout.html

另外,我已经翻译过了Google的Training课程,地址是:http://blog.csdn.net/allen315410/article/details/42875231

效果预览

 

创建抽屉布局

下面这个抽屉布局引用的是android.support.v4.DrawerLayout,类似于LineaLayout、RelativeLayout等布局一样定义,在DrawerLayout内部再定义3个布局,分别是管理主界面的FrameLayout,此布局用来展示界面切换的Fragment,下面是ListView,用来展示菜单列表,最后是一个RelativeLayout,用来展示右边的布局,布局代码如下:

  1. <android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2. android:id="@+id/drawer_layout"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent" >
  5. <FrameLayout
  6. android:id="@+id/content_frame"
  7. android:layout_width="match_parent"
  8. android:layout_height="match_parent" />
  9. <ListView
  10. android:id="@+id/left_drawer"
  11. android:layout_width="200dp"
  12. android:layout_height="match_parent"
  13. android:layout_gravity="start"
  14. android:background="#111"
  15. android:choiceMode="singleChoice"
  16. android:divider="@android:color/transparent"
  17. android:dividerHeight="0dp" />
  18. <RelativeLayout
  19. android:id="@+id/right_drawer"
  20. android:layout_width="220dp"
  21. android:layout_height="match_parent"
  22. android:layout_gravity="end"
  23. android:background="#111"
  24. android:gravity="center_horizontal" >
  25. <TextView
  26. android:layout_width="wrap_content"
  27. android:layout_height="wrap_content"
  28. android:text="这是右边栏"
  29. android:textColor="@android:color/white"
  30. android:textSize="24sp" />
  31. </RelativeLayout>
  32. </android.support.v4.widget.DrawerLayout>

这个布局文件示范了一些重要的布局特征.

  • 主要内容的视图(FrameLayout)必须是DrawLayout的第一个子元素, 因为导航抽屉是在主要内容视图的上面.
  • 主要内容视图设置为匹配父视图的宽度和高度, 因为它代表了整个界面导航抽屉是隐藏的.
  • 抽屉视图(ListView)必须指定其水平重力与android:layout_gravity属性。支持从右到左(RTL)语言,指定值与
    "start" 代替
    "left"(所以抽屉里出现在布局的右侧当布局是RTL时).这里将ListView设置为左边栏菜单,所以android:layout_gravity属性设置为“start”,将RelativeLayout设置为右边栏,设置android:layout_gravity属性为“end”.
  • 抽屉视图指定其宽度用dp单位和高度匹配父视图。抽屉里的宽度不能超过320 dp, 所以用户总是可以看到主要内容视图的一部分。

初始化抽屉列表

正如上述所讲,因为DrawerLayout里包含一个ListView作为左边栏侧滑菜单,所以我们需要首先初始化这个抽屉列表,并且为这个列表适配上数据,数据适配器使用的是最简单的ArrayAdapter,模拟数据被简单的定义在res/values/strings.xml里,如下:

  1. <string-array name="menu_array">
  2. <item>Menu 1</item>
  3. <item>Menu 2</item>
  4. <item>Menu 3</item>
  5. <item>Menu 4</item>
  6. </string-array>

在Java代码中,首先创建一个MainActivity继承了android.support.v4.app.FragmentActivity,因为后续中需要进行Fragment之间的切换。

  1. protected void onCreate(Bundle savedInstanceState) {
  2. super.onCreate(savedInstanceState);
  3. setContentView(R.layout.activity_main);
  4. ......
  5. // 初始化菜单列表
  6. mMenuTitles = getResources().getStringArray(R.array.menu_array);
  7. mMenuListView.setAdapter(new ArrayAdapter<String>(this, R.layout.drawer_list_item, mMenuTitles));
  8. mMenuListView.setOnItemClickListener(new DrawerItemClickListener());
  9. ......
  10. }

处理导航点击事件

当用户选择了抽屉列表里面的一个Item时, 系统调用onItemClickListener上的onItemClick(),
给setOnItemClickListener()你在onItemClick()方法里面做什么,在下面的例子中,
选择每一个Item都会在主要内容的布局中插入一个不同的Fragment.并且将导航列表的内容传递给Fragment中显示出来,下面是部分代码:

  1. /**
  2. * ListView上的Item点击事件
  3. *
  4. */
  5. private class DrawerItemClickListener implements ListView.OnItemClickListener {
  6. @Override
  7. public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
  8. selectItem(position);
  9. }
  10. }
  11. /**
  12. * 切换主视图区域的Fragment
  13. *
  14. * @param position
  15. */
  16. private void selectItem(int position) {
  17. // TODO Auto-generated method stub
  18. Fragment fragment = new ContentFragment();
  19. Bundle args = new Bundle();
  20. switch (position) {
  21. case 0:
  22. args.putString("key", mMenuTitles[position]);
  23. break;
  24. case 1:
  25. args.putString("key", mMenuTitles[position]);
  26. break;
  27. case 2:
  28. args.putString("key", mMenuTitles[position]);
  29. break;
  30. case 3:
  31. args.putString("key", mMenuTitles[position]);
  32. break;
  33. default:
  34. break;
  35. }
  36. fragment.setArguments(args); // FragmentActivity将点击的菜单列表标题传递给Fragment
  37. FragmentManager fragmentManager = getSupportFragmentManager();
  38. fragmentManager.beginTransaction().replace(R.id.content_frame, fragment).commit();
  39. // 更新选择后的item和title,然后关闭菜单
  40. mMenuListView.setItemChecked(position, true);
  41. setTitle(mMenuTitles[position]);
  42. mDrawerLayout.closeDrawer(mMenuListView);
  43. }

开源material-menu的集成

细心的朋友也许会发现“网易新闻”v4.4客户端主页左上角上有个菜单“动态”的菜单按钮,显示流程是这样的,当菜单没有打开时,显示“三”这样的三条横线,当菜单打开(无论左右菜单)时,会显示“<-”这样的按钮,不停的变化,这样的效果是不是有点绚丽啊?!了解过Android5.0的朋友,应该会知道这种效果是使用了Android5.0新推出的Material

Design设计语言做出来的效果,那么该怎么模仿这个效果呢?不好意思,由于偷懒,我已经在牛牛的Github中找到了这样的效果——material-menu组件,该组件模拟出了Android5.0下的Material
Design效果,注意的是该组件中使用了JackWharton的NineOldAndroids动画效果。

material-menu主页:https://github.com/balysv/material-menu

NineOldAndroids主页:https://github.com/JakeWharton/NineOldAndroids

关于material-menu的使用可以参考其主页上的Demo和说明,集成时需要下载NineOldAndroids导出jar集成到项目中。下面是我使用的部分代码:

  1. protected void onCreate(Bundle savedInstanceState) {
  2. super.onCreate(savedInstanceState);
  3. setContentView(R.layout.activity_main);
  4. ......
  5. // 设置抽屉打开时,主要内容区被自定义阴影覆盖
  6. mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);
  7. // 设置ActionBar可见,并且切换菜单和内容视图
  8. getActionBar().setDisplayHomeAsUpEnabled(true);
  9. getActionBar().setHomeButtonEnabled(true);
  10. mMaterialMenuIcon = new MaterialMenuIcon(this, Color.WHITE, Stroke.THIN);
  11. mDrawerLayout.setDrawerListener(new DrawerLayout.SimpleDrawerListener() {
  12. @Override
  13. public void onDrawerSlide(View drawerView, float slideOffset) {
  14. showView = drawerView;
  15. if (drawerView == mMenuListView) {
  16. mMaterialMenuIcon.setTransformationOffset(MaterialMenuDrawable.AnimationState.BURGER_ARROW, isDirection_left ? 2 - slideOffset : slideOffset);
  17. } else if (drawerView == right_drawer) {
  18. mMaterialMenuIcon.setTransformationOffset(MaterialMenuDrawable.AnimationState.BURGER_ARROW, isDirection_right ? 2 - slideOffset : slideOffset);
  19. }
  20. }
  21. @Override
  22. public void onDrawerOpened(android.view.View drawerView) {
  23. if (drawerView == mMenuListView) {
  24. isDirection_left = true;
  25. } else if (drawerView == right_drawer) {
  26. isDirection_right = true;
  27. }
  28. }
  29. @Override
  30. public void onDrawerClosed(android.view.View drawerView) {
  31. if (drawerView == mMenuListView) {
  32. isDirection_left = false;
  33. } else if (drawerView == right_drawer) {
  34. isDirection_right = false;
  35. showView = mMenuListView;
  36. }
  37. }
  38. });
  39. ......
  40. }

此外,还需要关联一下meterial-menu的状态,需要覆盖Activity下的onPostCreate和onSaveInstanceState方法:

  1. /**
  2. * 根据onPostCreate回调的状态,还原对应的icon state
  3. */
  4. @Override
  5. protected void onPostCreate(Bundle savedInstanceState) {
  6. super.onPostCreate(savedInstanceState);
  7. mMaterialMenuIcon.syncState(savedInstanceState);
  8. }
  9. /**
  10. * 根据onSaveInstanceState回调的状态,保存当前icon state
  11. */
  12. @Override
  13. protected void onSaveInstanceState(Bundle outState) {
  14. mMaterialMenuIcon.onSaveInstanceState(outState);
  15. super.onSaveInstanceState(outState);
  16. }

添加ActionBar上的菜单按钮

为了尽量模拟出“网易新闻”v4.4客户端主页,我也在标题栏右上角添加一个小图标,为了能在点击这个小图标的时候弹出右边栏菜单,实现方式很简单,关于ActionBar上添加导航的知识可以在csdn上搜到一些解释或者上Android开发者官网查看源文档,我这里首先简单的在res/menu下main.xml中这样定义一个:

  1. <menu xmlns:android="http://schemas.android.com/apk/res/android" >
  2. <item
  3. android:id="@+id/action_personal"
  4. android:icon="@drawable/action_personal"
  5. android:orderInCategory="100"
  6. android:showAsAction="always"
  7. android:title="@string/action_personal"/>
  8. </menu>

完成定义操作后,需要加载菜单布局:

  1. /**
  2. * 加载菜单
  3. */
  4. @Override
  5. public boolean onCreateOptionsMenu(Menu menu) {
  6. // Inflate the menu; this adds items to the action bar if it is present.
  7. getMenuInflater().inflate(R.menu.main, menu);
  8. return true;
  9. }

标题栏导航点击事件处理

  1. /**
  2. * 点击ActionBar上菜单
  3. */
  4. @Override
  5. public boolean onOptionsItemSelected(MenuItem item) {
  6. int id = item.getItemId();
  7. switch (id) {
  8. case android.R.id.home:
  9. if (showView == mMenuListView) {
  10. if (!isDirection_left) { // 左边栏菜单关闭时,打开
  11. mDrawerLayout.openDrawer(mMenuListView);
  12. } else {// 左边栏菜单打开时,关闭
  13. mDrawerLayout.closeDrawer(mMenuListView);
  14. }
  15. } else if (showView == right_drawer) {
  16. if (!isDirection_right) {// 右边栏关闭时,打开
  17. mDrawerLayout.openDrawer(right_drawer);
  18. } else {// 右边栏打开时,关闭
  19. mDrawerLayout.closeDrawer(right_drawer);
  20. }
  21. }
  22. break;
  23. case R.id.action_personal:
  24. if (!isDirection_right) {// 右边栏关闭时,打开
  25. if (showView == mMenuListView) {
  26. mDrawerLayout.closeDrawer(mMenuListView);
  27. }
  28. mDrawerLayout.openDrawer(right_drawer);
  29. } else {// 右边栏打开时,关闭
  30. mDrawerLayout.closeDrawer(right_drawer);
  31. }
  32. break;
  33. default:
  34. break;
  35. }
  36. return super.onOptionsItemSelected(item);
  37. }

这段的逻辑有点绕,事实上我做的是这样的,需要保证主界面上只能最多显示一个菜单布局,当左边的菜单布局展示时,此时打开右边菜单布局时,需要隐藏左边菜单布局;同样,如果右边的菜单布局已经在展示的时候,这时需要打开左边菜单布局,必须首先隐藏掉右边的菜单布局。为了判断当前即将显示或者关闭的是哪个布局,我在全局变量中定义了showView用来标记当前即将显示或者关闭的视图,如果showView==mMenuListView,说明左边菜单布局是即将被显示或隐藏的,这时进一步判断菜单是视图mMenuListView的是否已经显示的标记isDirection_left,来打开或者关闭左边视图菜单。
      同样的道理,如果当前即将显示或者隐藏的是右边导航菜单的话,我们需要进一步判断右边导航是否已经显示,从而进行相关打开或隐藏的决定。

这里的逻辑似乎解释的有点乱,而且代码是分片段贴出来的,不利于理解,需要进一步理解的话,不妨继续看下面的部分,我已经贴出了所以的Java代码,注释也很详尽,可以方便理解,实在不行,还可以点击博客下方的下载链接,直接下载源码运行一下。

全部源码

  1. public class MainActivity extends FragmentActivity {
  2. /** DrawerLayout */
  3. private DrawerLayout mDrawerLayout;
  4. /** 左边栏菜单 */
  5. private ListView mMenuListView;
  6. /** 右边栏 */
  7. private RelativeLayout right_drawer;
  8. /** 菜单列表 */
  9. private String[] mMenuTitles;
  10. /** Material Design风格 */
  11. private MaterialMenuIcon mMaterialMenuIcon;
  12. /** 菜单打开/关闭状态 */
  13. private boolean isDirection_left = false;
  14. /** 右边栏打开/关闭状态 */
  15. private boolean isDirection_right = false;
  16. private View showView;
  17. @Override
  18. protected void onCreate(Bundle savedInstanceState) {
  19. super.onCreate(savedInstanceState);
  20. setContentView(R.layout.activity_main);
  21. mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
  22. mMenuListView = (ListView) findViewById(R.id.left_drawer);
  23. right_drawer = (RelativeLayout) findViewById(R.id.right_drawer);
  24. this.showView = mMenuListView;
  25. // 初始化菜单列表
  26. mMenuTitles = getResources().getStringArray(R.array.menu_array);
  27. mMenuListView.setAdapter(new ArrayAdapter<String>(this,
  28. R.layout.drawer_list_item, mMenuTitles));
  29. mMenuListView.setOnItemClickListener(new DrawerItemClickListener());
  30. // 设置抽屉打开时,主要内容区被自定义阴影覆盖
  31. mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow,
  32. GravityCompat.START);
  33. // 设置ActionBar可见,并且切换菜单和内容视图
  34. getActionBar().setDisplayHomeAsUpEnabled(true);
  35. getActionBar().setHomeButtonEnabled(true);
  36. mMaterialMenuIcon = new MaterialMenuIcon(this, Color.WHITE, Stroke.THIN);
  37. mDrawerLayout.setDrawerListener(new DrawerLayoutStateListener());
  38. if (savedInstanceState == null) {
  39. selectItem(0);
  40. }
  41. }
  42. /**
  43. * ListView上的Item点击事件
  44. *
  45. */
  46. private class DrawerItemClickListener implements
  47. ListView.OnItemClickListener {
  48. @Override
  49. public void onItemClick(AdapterView<?> parent, View view, int position,
  50. long id) {
  51. selectItem(position);
  52. }
  53. }
  54. /**
  55. * DrawerLayout状态变化监听
  56. */
  57. private class DrawerLayoutStateListener extends
  58. DrawerLayout.SimpleDrawerListener {
  59. /**
  60. * 当导航菜单滑动的时候被执行
  61. */
  62. @Override
  63. public void onDrawerSlide(View drawerView, float slideOffset) {
  64. showView = drawerView;
  65. if (drawerView == mMenuListView) {// 根据isDirection_left决定执行动画
  66. mMaterialMenuIcon.setTransformationOffset(
  67. MaterialMenuDrawable.AnimationState.BURGER_ARROW,
  68. isDirection_left ? 2 - slideOffset : slideOffset);
  69. } else if (drawerView == right_drawer) {// 根据isDirection_right决定执行动画
  70. mMaterialMenuIcon.setTransformationOffset(
  71. MaterialMenuDrawable.AnimationState.BURGER_ARROW,
  72. isDirection_right ? 2 - slideOffset : slideOffset);
  73. }
  74. }
  75. /**
  76. * 当导航菜单打开时执行
  77. */
  78. @Override
  79. public void onDrawerOpened(android.view.View drawerView) {
  80. if (drawerView == mMenuListView) {
  81. isDirection_left = true;
  82. } else if (drawerView == right_drawer) {
  83. isDirection_right = true;
  84. }
  85. }
  86. /**
  87. * 当导航菜单关闭时执行
  88. */
  89. @Override
  90. public void onDrawerClosed(android.view.View drawerView) {
  91. if (drawerView == mMenuListView) {
  92. isDirection_left = false;
  93. } else if (drawerView == right_drawer) {
  94. isDirection_right = false;
  95. showView = mMenuListView;
  96. }
  97. }
  98. }
  99. /**
  100. * 切换主视图区域的Fragment
  101. *
  102. * @param position
  103. */
  104. private void selectItem(int position) {
  105. Fragment fragment = new ContentFragment();
  106. Bundle args = new Bundle();
  107. switch (position) {
  108. case 0:
  109. args.putString("key", mMenuTitles[position]);
  110. break;
  111. case 1:
  112. args.putString("key", mMenuTitles[position]);
  113. break;
  114. case 2:
  115. args.putString("key", mMenuTitles[position]);
  116. break;
  117. case 3:
  118. args.putString("key", mMenuTitles[position]);
  119. break;
  120. default:
  121. break;
  122. }
  123. fragment.setArguments(args); // FragmentActivity将点击的菜单列表标题传递给Fragment
  124. FragmentManager fragmentManager = getSupportFragmentManager();
  125. fragmentManager.beginTransaction()
  126. .replace(R.id.content_frame, fragment).commit();
  127. // 更新选择后的item和title,然后关闭菜单
  128. mMenuListView.setItemChecked(position, true);
  129. setTitle(mMenuTitles[position]);
  130. mDrawerLayout.closeDrawer(mMenuListView);
  131. }
  132. /**
  133. * 点击ActionBar上菜单
  134. */
  135. @Override
  136. public boolean onOptionsItemSelected(MenuItem item) {
  137. int id = item.getItemId();
  138. switch (id) {
  139. case android.R.id.home:
  140. if (showView == mMenuListView) {
  141. if (!isDirection_left) { // 左边栏菜单关闭时,打开
  142. mDrawerLayout.openDrawer(mMenuListView);
  143. } else {// 左边栏菜单打开时,关闭
  144. mDrawerLayout.closeDrawer(mMenuListView);
  145. }
  146. } else if (showView == right_drawer) {
  147. if (!isDirection_right) {// 右边栏关闭时,打开
  148. mDrawerLayout.openDrawer(right_drawer);
  149. } else {// 右边栏打开时,关闭
  150. mDrawerLayout.closeDrawer(right_drawer);
  151. }
  152. }
  153. break;
  154. case R.id.action_personal:
  155. if (!isDirection_right) {// 右边栏关闭时,打开
  156. if (showView == mMenuListView) {
  157. mDrawerLayout.closeDrawer(mMenuListView);
  158. }
  159. mDrawerLayout.openDrawer(right_drawer);
  160. } else {// 右边栏打开时,关闭
  161. mDrawerLayout.closeDrawer(right_drawer);
  162. }
  163. break;
  164. default:
  165. break;
  166. }
  167. return super.onOptionsItemSelected(item);
  168. }
  169. /**
  170. * 根据onPostCreate回调的状态,还原对应的icon state
  171. */
  172. @Override
  173. protected void onPostCreate(Bundle savedInstanceState) {
  174. super.onPostCreate(savedInstanceState);
  175. mMaterialMenuIcon.syncState(savedInstanceState);
  176. }
  177. /**
  178. * 根据onSaveInstanceState回调的状态,保存当前icon state
  179. */
  180. @Override
  181. protected void onSaveInstanceState(Bundle outState) {
  182. mMaterialMenuIcon.onSaveInstanceState(outState);
  183. super.onSaveInstanceState(outState);
  184. }
  185. /**
  186. * 加载菜单
  187. */
  188. @Override
  189. public boolean onCreateOptionsMenu(Menu menu) {
  190. // Inflate the menu; this adds items to the action bar if it is present.
  191. getMenuInflater().inflate(R.menu.main, menu);
  192. return true;
  193. }
  194. }

源码请在这里下载

Android组件——使用DrawerLayout仿网易新闻v4.4侧滑菜单的更多相关文章

  1. Android Studio精彩案例(一)《ActionBar和 ViewPager版仿网易新闻客户端》

    转载本专栏文章,请注明出处,尊重原创 .文章博客地址:道龙的博客 为了能更好的分享高质量的文章,所以开设了此专栏.文章代码都以Android Studio亲测运行,读者朋友可在后面直接下载源码.该专栏 ...

  2. 类似掌盟的Tab页 Android 开源框架ViewPageIndicator 和 ViewPager 仿网易新闻客户端Tab标签 (转)

    原博客地址  :http://blog.csdn.net/xiaanming/article/details/10766053 本文转载,记录学习用,如有需要,请到原作者网站查看(上面这个网址) 之前 ...

  3. Android 开源框架ActionBarSherlock 和 ViewPager 仿网易新闻客户端

    转载请注明出处:http://blog.csdn.net/xiaanming/article/details/9971721 大家都知道Android的ActionBar是在3.0以上才有的,那么在3 ...

  4. Android应用经典主界面框架之二:仿网易新闻client、CSDN client (Fragment ViewPager)

    另外一种主界面风格则是以网易新闻.凤凰新闻以及新推出的新浪博客(阅读版)为代表.使用ViewPager+Fragment,即ViewPager里适配器里放的不是一般的View.而是Fragment.所 ...

  5. Android 开源框架ViewPageIndicator 和 ViewPager 仿网易新闻clientTab标签

    之前用JakeWharton的开源框架ActionBarSherlock和ViewPager实现了对网易新闻clientTab标签的功能,ActionBarSherlock是在3.0下面的机器支持Ac ...

  6. Android 开源框架ViewPageIndicator 和 ViewPager 仿网易新闻客户端Tab标签

    转载请注明出处:http://blog.csdn.net/xiaanming/article/details/10766053 之前用JakeWharton的开源框架ActionBarSherlock ...

  7. iOS仿网易新闻栏目拖动重排添加删除效果

    仿网易新闻栏目选择页面的基本效果,今天抽了点时间教大家如何实现UICollectionView拖动的效果! 其实实现起来并不复杂,这里只是基本的功能,没有实现细节上的修改,连UI都是丑丑的样子,随手画 ...

  8. 仿网易新闻app下拉标签选择菜单

    仿网易新闻app下拉标签选择菜单 仿网易新闻app下拉标签选择菜单,长按拖动排序,点击增删标签控件 ##示例  ##EasyTagDragView的使用 在layout布局里添加:  

  9. iOS界面-仿网易新闻左侧抽屉式交互 续(添加新闻内容页和评论页手势)

     本文转载至  http://blog.csdn.net/totogo2010/article/details/8637430       1.介绍 有的博友看了上篇博文iOS界面-仿网易新闻左侧抽屉 ...

随机推荐

  1. 读阮一峰《ECMAScript 6 入门》小结

    读阮一峰<ECMAScript 6 入门>小结,http://es6.ruanyifeng.com/ 1. ES6简介 Babel 是一个广泛使用的 ES6 转码器,可以将 ES6 代码转 ...

  2. SpringBoot+springmvc异步处理请求

    有两种情况,第一种是业务逻辑复杂,但不需要业务逻辑的结果,第二种是需要返回业务逻辑的处理结果 第一种比较简单,利用多线程处理业务逻辑,或者利用spring中@Asyn注解更简单, 使用@Asyn注解, ...

  3. 指示函数(indicator function) 的作用

    1. counter 指示函数常用于次数(满足某一断言或条件)的统计: 2. 二维的离散指示函数 ⇒ assignment solution xij∈{0,1},∑jxij=1 ∑jxij=1:行和为 ...

  4. docker构建一个简易镜像

    一 下载centos镜像 docker pull centos 二 启动镜像 [root@Centos-node3 ~]# docker run -it --name my_ng centos bas ...

  5. 1.12 Python基础知识 - 序列:字符串

    字符串是一个有序的字符集合,即字符序列.Pythpn内置数据类型str,用于字符串处理,使用单引号或双引号括起来的字符,就是字符常量,Python解释器会自动创建str型对象实例. 字符串的定义: 1 ...

  6. Python的主成分分析PCA算法

    这篇文章很不错:https://blog.csdn.net/u013082989/article/details/53792010 为什么数据处理之前要进行归一化???(这个一直不明白) 这个也很不错 ...

  7. 12、python单步调试工具pdb

    pdb 第4种方式是启动Python的调试器pdb,让程序以单步方式运行,可以随时查看运行状态.我们先准备好程序: # err.py s = '0' n = int(s) print(10 / n) ...

  8. 将一个类写成WebService服务的形式

    WebService是一种跨编程语言和跨操作系统平台的远程调用技术,主要解决不同语言写的应用程序之间.不同平台(linux/windows/andrid)之间的通信,即异构系统之间的通信. 常用的天气 ...

  9. Webpack学习手册

    多端阅读<Webpack官方文档>: 在PC/MAC上查看:下载w3cschool客户端,进入客户端后通过搜索当前教程手册的名称并下载,就可以查看当前离线教程文档.下载Webpack官方文 ...

  10. C#游戏开发高速入门 2.1 构建游戏场景

    C#游戏开发高速入门 2.1  构建游戏场景 假设已经计划好了要编写什么样的游戏,在打开Unity以后.要做的第一件事情就是构建游戏场景(Scene).游戏场景就是玩家游戏时,在游戏视图中看到的一切. ...