DrawerLayout、CoordinatorLayout、CollapsingToolbarLayout的使用--AndroidSupportDesign练手
先po一张效果图
PS:原谅题主的懒惰吧..
看着是不是很酷炫,那是因为5.0的动画做得好,代码其实没有多少,搞清楚这个布局的层次关系很重要。
废话不多说了,先来看布局文件
最外层是一个DrawerLayout,它里面可以嵌套(一个?)container和多个drawer
在这个demo中DrawerLayout包含了一个CoordinatorLayout , ListView , NavigationView
CoordinatorLayout 作为 container的根布局
listView和navigationview作为DarwerLayout中的darwer
在container中用CoordinatorLayout目的是为了我们在滑动recyclerview时,让顶部的appbarlayout中的组件产生响应
appbarlayout中的CollapsingToolbarLayout是用来控制toolbar和banner图片的响应效果
特别注意:为了使得Toolbar可以滑动,我们必须还得有个条件,就是CoordinatorLayout布局下包裹一个可以滑动的布局,比如 RecyclerView,NestedScrollView(经过测试,ListView,ScrollView不支持)具有滑动效果的组件。
下面的就是drawerLayout的使用注意事项了:
按情理来说,一个drawerLayout添加一个drawer就够了,可是脑洞一开,想着多加一个会怎样,尝试之后发现很好玩,以后可以各种乱入drawer了,哈哈哈。
因为做毕设的时候用的DrawerLayout还不是这样方便的,那会使用这个布局,设置起来麻烦很多,而现在的实现这个布局,布局文件设置好之后,只用三句话就搞定了,简单的可怕。
下面贴上源码,各位看官就自行分析吧:
主布局文件:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"> <android.support.design.widget.CoordinatorLayout
android:id="@+id/main_content"
android:layout_width="match_parent"
android:layout_height="match_parent"> <android.support.design.widget.AppBarLayout
android:id="@+id/app_bar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"> <android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/collapsing_toolbar_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:contentScrim="@android:color/transparent"
app:layout_scrollFlags="scroll|exitUntilCollapsed"> <ImageView
android:id="@+id/banner"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="banner"
android:scaleType="fitXY"
android:src="@mipmap/banner"
app:layout_collapseMode="parallax"
app:layout_collapseParallaxMultiplier="0.5" /> <android.support.v7.widget.Toolbar
android:id="@+id/tool_bar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@android:color/transparent"
app:layout_collapseMode="pin" />
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout> <android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_behavior="@string/appbar_scrolling_view_behavior" /> <android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/activity_vertical_margin"
android:src="@mipmap/ic_action_web_site"
app:borderWidth="0dp"
app:elevation="@dimen/fab_elevation"
app:layout_anchor="@id/app_bar_layout"
app:layout_anchorGravity="end|bottom"
app:layout_collapseMode="parallax"
app:layout_collapseParallaxMultiplier="0.7"
app:pressedTranslationZ="@dimen/fab_translation_z_pressed"
app:rippleColor="?attr/colorPrimary" />
</android.support.design.widget.CoordinatorLayout> <ListView
android:id="@+id/id_lv_left_menu"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="end"
android:paddingTop="0dp"
android:background="#ffffffff"
android:clipToPadding="false"
android:divider="@null"
android:listSelector="?attr/selectableItemBackground"
/> <!--<include-->
<!--android:layout_width="match_parent"-->
<!--android:layout_height="match_parent"-->
<!--android:layout_gravity="start"-->
<!--android:paddingTop="0dp"-->
<!--android:background="#ffffffff"-->
<!--android:clipToPadding="false"-->
<!--android:id="@+id/custom_drawer"-->
<!--layout="@layout/layout_listview_drawer" />--> <android.support.design.widget.NavigationView
android:id="@+id/navigation_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
app:headerLayout="@layout/drawer_header"
app:menu="@menu/menu_navigation_items" /> </android.support.v4.widget.DrawerLayout>
Activity文件:
package com.anhry.hcol.support.design.activity; import android.os.Bundle;
import android.support.design.widget.AppBarLayout;
import android.support.design.widget.CollapsingToolbarLayout;
import android.support.design.widget.CoordinatorLayout;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.NavigationView;
import android.support.design.widget.Snackbar;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.ListView; import com.anhry.hcol.support.design.adapter.LeftMenuListAdapter;
import com.anhry.hcol.support.design.adapter.MenuItemAdapter;
import com.anhry.hcol.support.design.module.LvMenuItem;
import com.yanbober.support_library_demo.R;
import com.yanbober.support_library_demo.RecyclerViewAdapter; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; /**
* @author HCol
* @email 282386589@qq.com
* @create 2015/8/25
* @modify 2015年8月29日17:29:04
*/
public class DesignDemoActivity extends AppCompatActivity { /**
* views
*/
private DrawerLayout mDrawerLayout;
private CoordinatorLayout mCoordinatorLayout;
private AppBarLayout mAppBarLayout;
private CollapsingToolbarLayout mCollapsingToolbarLayout;
private ImageView mImageView;
private Toolbar mToolbar;
private RecyclerView mRecyclerView;
private NavigationView mNavigationView;
private FloatingActionButton mFloatingActionButton;
private ImageView mRightNavigationBtn; private CoordinatorLayout mCustomDrawer;
private RecyclerView leftMenuList; private ListView mLvLeftMenu;
/**
* members
*/
private RecyclerViewAdapter mAdapter;
private LinearLayoutManager mRecyclerLayoutManager;
private LeftMenuListAdapter mLeftMenuListAdapter;
private List<LvMenuItem> dataSource;
private static final String BTN_RIGHT_MENU_TAG = "tag"; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); initViews();
} /**
* init views
*/
private void initViews() {
setContentView(R.layout.activity_my_design);
/* 抽屉形式界面的的两个布局控件
*
* DrawerLayout 做根布局使用
* 因为要显示的内容界面和抽屉视图(NavigationView)是包含在此layout之下的
*
* NavigationView 抽屉布局中的抽屉视图,有源码分析他的实现其实就是一个ListView
* 而这里用的是原生的组件,所以在Menu目录下配置好要显示的条目,引用即可,非常方便.
*
* ref:http://blog.csdn.net/lmj623565791/article/details/46405409
*
* */
// 原生DrawerLayout
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout); // 利用ListView仿制的Drawer
mLvLeftMenu = (ListView) findViewById(R.id.id_lv_left_menu);
setUpDrawer(); // 不用在意这一块
// mCustomDrawer = (CoordinatorLayout) findViewById(R.id.custom_drawer);
// leftMenuList = (RecyclerView) findViewById(R.id.rv_left_menu);
// dataSource = new ArrayList<>(
// Arrays.asList(
// new LvMenuItem(R.mipmap.ic_action_web_site, "Home"),
// new LvMenuItem(R.mipmap.ic_action_web_site, "Messages"),
// new LvMenuItem(R.mipmap.ic_action_web_site, "Friends"),
// new LvMenuItem(R.mipmap.ic_action_web_site, "Discussion"),
// new LvMenuItem(R.mipmap.ic_action_web_site, "Discussion"),
// new LvMenuItem(R.mipmap.ic_action_web_site, "Discussion"),
// new LvMenuItem(R.mipmap.ic_action_web_site, "Discussion"),
// new LvMenuItem(R.mipmap.ic_action_web_site, "Discussion"),
// new LvMenuItem(),
// new LvMenuItem("Sub Items"),
// new LvMenuItem(R.mipmap.ic_action_web_site, "Sub Item 1"),
// new LvMenuItem(R.mipmap.ic_action_web_site, "Sub Item 2")
// ));
// mLeftMenuListAdapter = new LeftMenuListAdapter(this, dataSource);
// mRecyclerLayoutManager = new LinearLayoutManager(this);
// leftMenuList.setAdapter(mLeftMenuListAdapter);
// leftMenuList.setLayoutManager(mRecyclerLayoutManager); mNavigationView = (NavigationView) findViewById(R.id.navigation_view);
mNavigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(MenuItem menuItem) {
mDrawerLayout.closeDrawers();
return true;
}
});
/* 下面就是抽屉布局中[内容布局]的重点了
*
* CoordinatorLayout 协调者布局
* AppBarLayout 导航栏布局
* CollapsingToolbarLayout ToolBar的可坍塌布局
*
* 首先,这三个布局有什么用呢?
*
* CoordinatorLayout
* 官方文档介绍说是一个增强版的FrameLayout
* 有两种主要的用途:
* 1. 作为一个顶层布局文件来使用
* 2. 作为一个有[多个互动视图]的容器
* 就是当某一视图有特殊行为动作时,其他子视图会进行相应的动作反应。INTERACTION
*
* AppBarLayout
* 一个模块化的布局文件,可以用来装载一切属于AppBar的组件
*
* CollapsingToolbarLayout
*
* CollapsingToolbarLayout is a wrapper for Toolbar which implements a collapsing app bar.
* It is designed to be used as a direct child of a AppBarLayout.
*
* 官方说,它的诞生主要是用来为toolbar锦上添花用的
* 被设计来作为AppBarLayout的亲儿子来使用
*
* */
mCoordinatorLayout = (CoordinatorLayout) findViewById(R.id.main_content);
mAppBarLayout = (AppBarLayout) findViewById(R.id.app_bar_layout);
mCollapsingToolbarLayout = (CollapsingToolbarLayout) findViewById(R.id.collapsing_toolbar_layout);
mImageView = (ImageView) findViewById(R.id.banner);
mToolbar = (Toolbar) findViewById(R.id.tool_bar); // 创建右边导航按钮
ensureRightButtonView();
mToolbar.setNavigationIcon(R.mipmap.ic_drawer);
mToolbar.addView(mRightNavigationBtn);
mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mDrawerLayout.openDrawer(GravityCompat.START);
}
});
mCollapsingToolbarLayout.setTitle("CollapsingTitle");
/* init RecyclerView */
mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);
mAdapter = new RecyclerViewAdapter(this);
mRecyclerView.setAdapter(mAdapter);
mRecyclerLayoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(mRecyclerLayoutManager); mFloatingActionButton = (FloatingActionButton)findViewById(R.id.fab);
mFloatingActionButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Snackbar.make(mRecyclerView , "papa i'm here" , Snackbar.LENGTH_LONG).show();
}
});
} private void setUpDrawer() {
LayoutInflater inflater = LayoutInflater.from(this);
mLvLeftMenu.addHeaderView(inflater.inflate(R.layout.drawer_header, mLvLeftMenu, false));
mLvLeftMenu.setAdapter(new MenuItemAdapter(this));
mLvLeftMenu.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
mDrawerLayout.closeDrawers();
}
});
} private void ensureRightButtonView() {
if (mRightNavigationBtn == null) {
mRightNavigationBtn = new ImageButton(this, null,
android.support.v7.appcompat.R.attr.toolbarNavigationButtonStyle);
final Toolbar.LayoutParams lp = generateDefaultLayoutParams();
lp.gravity = GravityCompat.END | (Gravity.TOP & Gravity.VERTICAL_GRAVITY_MASK);
mRightNavigationBtn.setImageResource(R.mipmap.ic_drawer);
mRightNavigationBtn.setLayoutParams(lp);
mRightNavigationBtn.setTag(BTN_RIGHT_MENU_TAG);
mRightNavigationBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mDrawerLayout.openDrawer(GravityCompat.END);
}
});
}
} private Toolbar.LayoutParams generateDefaultLayoutParams() {
return new Toolbar.LayoutParams(Toolbar.LayoutParams.WRAP_CONTENT, Toolbar.LayoutParams.WRAP_CONTENT);
}
}
drawer head:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#000000"
android:gravity="center_horizontal"
android:orientation="vertical"
android:padding="13dp"> <ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/icon_people" /> <TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:text="UserName"
android:textColor="?attr/colorAccent"
android:textSize="24sp" />
</LinearLayout>
ListViewAdapter:
public class MenuItemAdapter extends BaseAdapter {
private final int mIconSize;
private LayoutInflater mInflater;
private Context mContext; public MenuItemAdapter(Context context) {
mInflater = LayoutInflater.from(context);
mContext = context; mIconSize = context.getResources().getDimensionPixelSize(R.dimen.abc_dialog_padding_material);//24dp
} private List<LvMenuItem> mItems = new ArrayList<LvMenuItem>(
Arrays.asList(
new LvMenuItem(R.mipmap.ic_action_web_site, "Home"),
new LvMenuItem(R.mipmap.ic_action_web_site, "Messages"),
new LvMenuItem(R.mipmap.ic_action_web_site, "Friends"),
new LvMenuItem(R.mipmap.ic_action_web_site, "Discussion"),
new LvMenuItem(),
new LvMenuItem("Sub Items"),
new LvMenuItem(R.mipmap.ic_action_web_site, "Sub Item 1"),
new LvMenuItem(R.mipmap.ic_action_web_site, "Sub Item 2")
)); @Override
public int getCount() {
return mItems.size();
} @Override
public Object getItem(int position) {
return mItems.get(position);
} @Override
public long getItemId(int position) {
return position;
} @Override
public int getViewTypeCount() {
return 3;
} @Override
public int getItemViewType(int position) {
return mItems.get(position).type;
} @Override
public View getView(int position, View convertView, ViewGroup parent) {
LvMenuItem item = mItems.get(position);
switch (item.type) {
case LvMenuItem.TYPE_NORMAL:
if (convertView == null) {
convertView = mInflater.inflate(R.layout.design_drawer_item, parent,
false);
}
TextView itemView = (TextView) convertView;
itemView.setText(item.name);
Drawable icon = mContext.getResources().getDrawable(item.icon);
setIconColor(icon);
if (icon != null) {
icon.setBounds(0, 0, mIconSize, mIconSize);
TextViewCompat.setCompoundDrawablesRelative(itemView, icon, null, null, null);
} break;
case LvMenuItem.TYPE_NO_ICON:
if (convertView == null) {
convertView = mInflater.inflate(R.layout.design_drawer_item_subheader,
parent, false);
}
TextView subHeader = (TextView) convertView;
subHeader.setText(item.name);
break;
case LvMenuItem.TYPE_SEPARATOR:
if (convertView == null) {
convertView = mInflater.inflate(R.layout.design_drawer_item_separator,
parent, false);
}
break;
} return convertView;
} public void setIconColor(Drawable icon) {
int textColorSecondary = android.R.attr.textColorSecondary;
TypedValue value = new TypedValue();
if (!mContext.getTheme().resolveAttribute(textColorSecondary, value, true)) {
return;
}
int baseColor = mContext.getResources().getColor(value.resourceId);
icon.setColorFilter(baseColor, PorterDuff.Mode.MULTIPLY);
}
}
Item:
public class LvMenuItem { public LvMenuItem(int icon, String name) {
this.icon = icon;
this.name = name; if (icon == NO_ICON && TextUtils.isEmpty(name)) {
type = TYPE_SEPARATOR;
} else if (icon == NO_ICON) {
type = TYPE_NO_ICON;
} else {
type = TYPE_NORMAL;
} if (type != TYPE_SEPARATOR && TextUtils.isEmpty(name)) {
throw new IllegalArgumentException("you need set a name for a non-SEPARATOR item");
}
} public LvMenuItem(String name) {
this(NO_ICON, name);
} public LvMenuItem() {
this(null);
} public static final int NO_ICON = 0;
public static final int TYPE_NORMAL = 0;
public static final int TYPE_NO_ICON = 1;
public static final int TYPE_SEPARATOR = 2; public int type;
public String name;
public int icon;
}
Item的资源文件:
design_drawer_item_separator:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"> <View android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?android:attr/listDivider"/> </FrameLayout>
design_drawer_item_subheader:
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="?attr/listPreferredItemHeightSmall"
android:gravity="center_vertical|start"
android:maxLines="1"
android:paddingLeft="?attr/listPreferredItemPaddingLeft"
android:paddingRight="?attr/listPreferredItemPaddingRight"
android:textAppearance="?attr/textAppearanceListItem"
android:textColor="?android:textColorSecondary"/>
design_drawer_item:
<?xml version="1.0" encoding="utf-8"?>
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="?attr/listPreferredItemHeightSmall"
android:paddingLeft="?attr/listPreferredItemPaddingLeft"
android:paddingRight="?attr/listPreferredItemPaddingRight"
android:drawablePadding="32dp"
android:gravity="center_vertical|start"
android:maxLines="1"
android:textAppearance="?attr/textAppearanceListItem"
android:textColor="?android:attr/textColorPrimary"/>
参考资料:
http://www.2cto.com/kf/201506/409067.html
http://www.open-open.com/lib/view/open1433385856119.html#_label8
http://blog.csdn.net/lmj623565791/article/details/46405409
PS:为什么放多个drawer,而drawerLayout打开drawer的时候不会混乱呢?
没事就看看源码,反正又不要钱..
DrawerLayout、CoordinatorLayout、CollapsingToolbarLayout的使用--AndroidSupportDesign练手的更多相关文章
- Python学习路径及练手项目合集
Python学习路径及练手项目合集 https://zhuanlan.zhihu.com/p/23561159
- Cocos2d-Lua (练手) 微信打飞机
学习下lua,目前入门级,使用版本为 v3.3 Final For Win,空闲时间不足,只能断断续续写点东西. 一.子弹效果 子弹只做了一种,扇形发射,可以增加扇形大小,子弹的 ...
- web前端学习部落22群分享给需要前端练手项目
前端学习还是很有趣的,可以较快的上手然后自己开发一些好玩的项目来练手,网上也可以一抓一大把关于前端开发的小项目,可是还是有新手在学习的时候不知道可以做什么,以及怎么做,因此,就整理了一些前端项目教程, ...
- webpack练手项目之easySlide(三):commonChunks(转)
Hello,大家好. 在之前两篇文章中: webpack练手项目之easySlide(一):初探webpack webpack练手项目之easySlide(二):代码分割 与大家分享了webpack的 ...
- webpack练手项目之easySlide(二):代码分割(转)
在上一篇 webpack练手项目之easySlide(一):初探webpack 中我们一起为大家介绍了webpack的基本用法,使用webpack对前端代码进行模块化打包. 但是乍一看webpack ...
- webpack练手项目之easySlide(一):初探webpack (转)
最近在学习webpack,正好拿了之前做的一个小组件,图片轮播来做了下练手,让我们一起来初步感受下webpack的神奇魅力. webpack是一个前端的打包管理工具,大家可以前往:http:/ ...
- JAVA大数类练手
今天突然看到了OJ上的大数类题目,由于学习了一点大数类的知识.果断水了6道题......都是非常基础的.就当的练手的吧. 学到的只是一些大数类的基本操作.以后多做点这样的题,争取熟练运用水大数题... ...
- Python之路【第二十四篇】:Python学习路径及练手项目合集
Python学习路径及练手项目合集 Wayne Shi· 2 个月前 参照:https://zhuanlan.zhihu.com/p/23561159 更多文章欢迎关注专栏:学习编程. 本系列Py ...
- node论坛练手
当时学node,自己写了个论坛练手,现在看还是有很多问题,有时间好好改改 https://github.com/hitbs228/countdown
随机推荐
- Docker镜像与仓库(一)
Docker镜像与仓库(一) Docker镜像与仓库(一) 如何查找镜像? Docker Hub https://registry.hub.docker.com docker search [OPTI ...
- sp<> 强指针类的用法
在android 中可以广泛看到的template<typename T>, class Sp 句柄类实际上是android 为实现垃圾回收机制的智能指针.智能指针是c++ 中的一个概念 ...
- windows常用环境变量
%ALLUSERSPROFILE%列出所有用户Profile文件位置. %APPDATA%列出应用程序数据的默认存放位置. %CD%列出当前目录. %CLIENTNAME%列出联接到终端服务会话时客户 ...
- Perfmon 介绍
1.UI 1.笔图标,可以把视图里的细线加粗. 2.加号图标.可以为视图添加新的记数器. 3.操作-->属性.可以用于设置默认的采样时间. 2.增加计数据器页面 1.一个计数据器会包涵多个对象. ...
- ODI KM二次开发手册
ODI KM二次开发手册 分类: ODI(16) 目录(?)[+] 1 引言 1.1 编写目的 本手册面向的读者对象为具备数据集成业务知识及对ODI操作了解的开发人员,作为其完成基于ODI基础上K ...
- 关于“#ifdef __cplusplus”
CC++语言在编译的时候为了解决函数的多态问题,会将函数名和参数联合起来生成一个中间的函数名称,而C语言则不会,因此会造成链接时找不到对应函数的情况,此时C函数就需要用extern “C”进行链接指定 ...
- Unix/Linux环境C编程入门教程(1) Solaris 11 64bit环境搭建
Unix/Linux版本众多,我们推荐Unix/Linux初学者选用几款典型的Unix/Linux操作系统进行学习. 本文就带大家来安装Solaris 11 64位并且配置好C/C++开发环境 本文所 ...
- poj1563---蜗牛爬井
#include <stdio.h> #include <stdlib.h> int main() { int dayTh; float Udis,currentHeight, ...
- 弹飞DZY(思维,打表,还没过全,先放着)
弹飞DZYDescription某天,机智的ZZC发明了一种超级弹力装置,为了在他的朋友DZY面前显摆,他邀请DZY一起玩个游戏.游戏一开始,ZZC在地上沿着一条直线摆上n个装置,每个装置设定初始弹力 ...
- Roland钢琴开发中音符值、度、与音名之间的转换算法
在Roland钢琴伴侣的开发中,首先将mid文件解析出来取到每一个音符的起始时间,每一个音符的时值,音符值(比如中央C的值是60),在绘五线谱的时候需要将每一个音符值与它对应的度(octave)和音名 ...