Android Layout 布局动画的介绍
2016-04-04 10:05
543 查看
转载请注明出处:/article/7809138.html
上一篇博文我们详细地学习了如何使用ValueAnimator和ObjectAnimator实现非常炫的动画效果,不过,都只是对View实现的动画,那今天我们来学习Property Animation如何为ViewGroup对象的动画显示提供支持。
APPEARING —— 元素在容器中显现时需要动画显示。
CHANGE_APPEARING —— 由于容器中要显现一个新的元素,其它元素的变化需要动画显示。
DISAPPEARING —— 元素在容器中消失时需要动画显示。
CHANGE_DISAPPEARING —— 由于容器中某个元素要消失,其它元素的变化需要动画显示。
其实这四种动画形式也很好理解,举个例子,我们有一个GridLayout中有多个Button对象,如果需要删除其中一个Button对象的话,该Button对象可以设置动画(即DISAPPEARING 动画形式),Layout中的其它Button对象此时移动到新的位置的过程中也可以设置相关的动画(即CHANGE_DISAPPEARING
动画形式),如图下:
而当需要为Layout添加一个新的Button对象时,此时我们可以为这个 新添加的Button对象设置动画(即APPEARING 动画形式),Layout中的其它Button对象此时移动到新的位置过程也可以设置相关的动画(即CHANGE_APPEARING动画形式 ),如图下:
那基本了解了这四种动画形式后,我们又应该如何使用呢?LayoutTransition类中有一个setAnimator(int transitionType, Animator animator)用于添加动画以及设置动画形式类型,在开发当中,我们只需要确定好需要在不同的动画类型中显示什么动画,然后创建并设置好相关的动画对象,最后使用该方法将两者进行绑定就行。那废话不多说,下面我们通过一个例子来学习一下如何为Layout添加动画。代码实例在文章末尾提供下载,
下面是LayoutAnimatorFragment主界面及和主要功能代码,如下:
[java] view
plaincopy
/**
* @author AndroidLeaf
*ViewGroup中Layout的动画实现
*主要知识点:
*调用 LayoutTransition 对象的 setAnimator() 方法来定义下列动画方式,调用参数是 Animator
*对象和以下 LayoutTransition 常量:
* (1)APPEARING —— 元素在容器中显现时需要动画显示。
* (2)CHANGE_APPEARING —— 由于容器中要显现一个新的元素,其它元素的变化需要动画显示。
* (3)DISAPPEARING —— 元素在容器中消失时需要动画显示。
* (4)CHANGE_DISAPPEARING —— 由于容器中某个元素要消失,其它元素的变化需要动画显示。
*/
public class LayoutAnimatorFragment extends Fragment implements OnClickListener{
private Button mButtonAdd;
private Button mButtonReset;
private GridLayout mGridLayout;
private int buttonNumbers = 1;
private LayoutTransition mLayoutTransition;
@Override
public void onActivityCreated(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onActivityCreated(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
View rootView = inflater.inflate(R.layout.fragment_layoutanimator, container, false);
initViews(rootView);
return rootView;
}
public void initViews(View rootView){
mButtonAdd = (Button)rootView.findViewById(R.id.layout_animator_addbutton);
mButtonAdd.setOnClickListener(this);
mButtonReset = (Button)rootView.findViewById(R.id.layout_animator_resetbutton);
mButtonReset.setOnClickListener(this);
mGridLayout = (GridLayout)rootView.findViewById(R.id.layout_animator_gridview);
mLayoutTransition = new LayoutTransition();
//为GridLayout设置mLayoutTransition对象
mGridLayout.setLayoutTransition(mLayoutTransition);
mLayoutTransition.setStagger(LayoutTransition.CHANGE_APPEARING, 30);
mLayoutTransition.setStagger(LayoutTransition.CHANGE_DISAPPEARING, 30);
//设置每个动画持续的时间
mLayoutTransition.setDuration(300);
//初始化自定义的动画效果
customLayoutTransition();
}
@Override
public void onPause() {
// TODO Auto-generated method stub
super.onPause();
}
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
switch (v.getId()) {
case R.id.layout_animator_addbutton:
addButton();
break;
case R.id.layout_animator_resetbutton:
resetButton();
break;
default:
break;
}
}
/**
* 增加Button
*/
public void addButton(){
Button mButton = new Button(getActivity());
LinearLayout.LayoutParams mLayoutParams = new LinearLayout.LayoutParams(50, 50);
mButton.setLayoutParams(mLayoutParams);
mButton.setText(String.valueOf(buttonNumbers++));
mButton.setTextColor(Color.rgb(0, 0, 0));
if(buttonNumbers % 2 == 1){
mButton.setBackgroundColor(Color.rgb(45, 118, 87));
}else{
mButton.setBackgroundColor(Color.rgb(225, 24, 0));
}
mButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
mGridLayout.removeView(v);
}
});
mGridLayout.addView(mButton, Math.min(1, mGridLayout.getChildCount()));
}
/**
* 删除所有的Button,重置GridLayout
*/
public void resetButton(){
mGridLayout.removeAllViews();
buttonNumbers = 1;
}
public void customLayoutTransition(){
/**
* Add Button
* LayoutTransition.APPEARING
* 增加一个Button时,设置该Button的动画效果
*/
ObjectAnimator mAnimatorAppearing = ObjectAnimator.ofFloat(null, "rotationY", 90.0f,0.0f)
.setDuration(mLayoutTransition.getDuration(LayoutTransition.APPEARING));
//为LayoutTransition设置动画及动画类型
mLayoutTransition.setAnimator(LayoutTransition.APPEARING, mAnimatorAppearing);
mAnimatorAppearing.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
// TODO Auto-generated method stub
super.onAnimationEnd(animation);
View view = (View) ((ObjectAnimator) animation).getTarget();
view.setRotationY(0.0f);
}
});
/**
* Add Button
* LayoutTransition.CHANGE_APPEARING
* 当增加一个Button时,设置其他Button的动画效果
*/
PropertyValuesHolder pvhLeft =
PropertyValuesHolder.ofInt("left", 0, 1);
PropertyValuesHolder pvhTop =
PropertyValuesHolder.ofInt("top", 0, 1);
PropertyValuesHolder pvhRight =
PropertyValuesHolder.ofInt("right", 0, 1);
PropertyValuesHolder pvhBottom =
PropertyValuesHolder.ofInt("bottom", 0, 1);
PropertyValuesHolder mHolderScaleX = PropertyValuesHolder.ofFloat("scaleX", 1.0f,0.0f,1.0f);
PropertyValuesHolder mHolderScaleY = PropertyValuesHolder.ofFloat("scaleY", 1.0f,0.0f,1.0f);
ObjectAnimator mObjectAnimatorChangeAppearing = ObjectAnimator.ofPropertyValuesHolder(this, pvhLeft,
pvhTop,pvhRight,pvhBottom,mHolderScaleX,mHolderScaleY).setDuration(mLayoutTransition
.getDuration(LayoutTransition.CHANGE_APPEARING));
mLayoutTransition.setAnimator(LayoutTransition.CHANGE_APPEARING, mObjectAnimatorChangeAppearing);
mObjectAnimatorChangeAppearing.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
// TODO Auto-generated method stub
super.onAnimationEnd(animation);
View view = (View) ((ObjectAnimator) animation).getTarget();
view.setScaleX(1f);
view.setScaleY(1f);
}
});
/**
* Delete Button
* LayoutTransition.DISAPPEARING
* 当删除一个Button时,设置该Button的动画效果
*/
ObjectAnimator mObjectAnimatorDisAppearing = ObjectAnimator.ofFloat(null, "rotationX", 0.0f,90.0f)
.setDuration(mLayoutTransition.getDuration(LayoutTransition.DISAPPEARING));
mLayoutTransition.setAnimator(LayoutTransition.DISAPPEARING, mObjectAnimatorDisAppearing);
mObjectAnimatorDisAppearing.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
// TODO Auto-generated method stub
super.onAnimationEnd(animation);
View view = (View) ((ObjectAnimator) animation).getTarget();
view.setRotationX(0.0f);
}
});
/**
* Delete Button
* LayoutTransition.CHANGE_DISAPPEARING
* 当删除一个Button时,设置其它Button的动画效果
*/
//Keyframe 对象中包含了一个时间/属性值的键值对,用于定义某个时刻的动画状态。
Keyframe mKeyframeStart = Keyframe.ofFloat(0.0f, 0.0f);
Keyframe mKeyframeMiddle = Keyframe.ofFloat(0.5f, 180.0f);
Keyframe mKeyframeEndBefore = Keyframe.ofFloat(0.999f, 360.0f);
Keyframe mKeyframeEnd = Keyframe.ofFloat(1.0f, 0.0f);
PropertyValuesHolder mPropertyValuesHolder = PropertyValuesHolder.ofKeyframe("rotation",
mKeyframeStart,mKeyframeMiddle,mKeyframeEndBefore,mKeyframeEnd);
ObjectAnimator mObjectAnimatorChangeDisAppearing = ObjectAnimator.ofPropertyValuesHolder(this, pvhLeft,pvhTop,pvhRight,pvhBottom,mPropertyValuesHolder)
.setDuration(mLayoutTransition.getDuration(LayoutTransition.CHANGE_DISAPPEARING));
mLayoutTransition.setAnimator(LayoutTransition.CHANGE_DISAPPEARING, mObjectAnimatorChangeDisAppearing);
mObjectAnimatorChangeDisAppearing.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
// TODO Auto-generated method stub
super.onAnimationEnd(animation);
View view = (View) ((ObjectAnimator) animation).getTarget();
view.setRotation(0.0f);
}
});
}
}
LayoutAnimatorFragment的界面布局fragment_layoutanimator.xml代码如下:
[html] view
plaincopy
<LinearLayout 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:background="@color/view_animation_background"
android:orientation="vertical"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
>
<Button
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:text="Add Button"
android:id="@+id/layout_animator_addbutton"
/>
<Button
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:text="Reset Button"
android:id="@+id/layout_animator_resetbutton"
/>
</LinearLayout>
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<GridLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:columnCount="5"
android:animateLayoutChanges="true"
android:id="@+id/layout_animator_gridview"
/>
</ScrollView>
</LinearLayout>
布局界面比较简单,唯一要注意的是GridLayout布局中的android:animateLayoutChanges属性,该属性的值为true或false,true代表当前Layout的布局发生改变时使用动画效果,false则不使用。
最后我们运行程序,看一下运行及操作效果图:
小伙伴们,有没感觉上面的动画效果比较炫,哈哈,想要实现的伙伴们赶紧动手吧!
源代码下载,请戳下面:
GITHUB下载
CSDN下载
上一篇博文我们详细地学习了如何使用ValueAnimator和ObjectAnimator实现非常炫的动画效果,不过,都只是对View实现的动画,那今天我们来学习Property Animation如何为ViewGroup对象的动画显示提供支持。
LayoutTransition 类介绍
我们先来认识一个重要的类--LayoutTransition,该类是Android API提供的用于动画显示ViewGroup中的Layout的帮助类,我们可以使用该类设置动画并绑定目标Layout。那一般在什么情况下为Layout设置动画效果呢?比方说,如果我们需要对一个Layout实现动态地添加或删除子View对象,那么我们可以分别为需添加或删除的View对象在移动到新的位置的过程添加动画形式。一般地,Layout中的View对象有四种动画变化的形式,如下:APPEARING —— 元素在容器中显现时需要动画显示。
CHANGE_APPEARING —— 由于容器中要显现一个新的元素,其它元素的变化需要动画显示。
DISAPPEARING —— 元素在容器中消失时需要动画显示。
CHANGE_DISAPPEARING —— 由于容器中某个元素要消失,其它元素的变化需要动画显示。
其实这四种动画形式也很好理解,举个例子,我们有一个GridLayout中有多个Button对象,如果需要删除其中一个Button对象的话,该Button对象可以设置动画(即DISAPPEARING 动画形式),Layout中的其它Button对象此时移动到新的位置的过程中也可以设置相关的动画(即CHANGE_DISAPPEARING
动画形式),如图下:
而当需要为Layout添加一个新的Button对象时,此时我们可以为这个 新添加的Button对象设置动画(即APPEARING 动画形式),Layout中的其它Button对象此时移动到新的位置过程也可以设置相关的动画(即CHANGE_APPEARING动画形式 ),如图下:
那基本了解了这四种动画形式后,我们又应该如何使用呢?LayoutTransition类中有一个setAnimator(int transitionType, Animator animator)用于添加动画以及设置动画形式类型,在开发当中,我们只需要确定好需要在不同的动画类型中显示什么动画,然后创建并设置好相关的动画对象,最后使用该方法将两者进行绑定就行。那废话不多说,下面我们通过一个例子来学习一下如何为Layout添加动画。代码实例在文章末尾提供下载,
下面是LayoutAnimatorFragment主界面及和主要功能代码,如下:
[java] view
plaincopy
/**
* @author AndroidLeaf
*ViewGroup中Layout的动画实现
*主要知识点:
*调用 LayoutTransition 对象的 setAnimator() 方法来定义下列动画方式,调用参数是 Animator
*对象和以下 LayoutTransition 常量:
* (1)APPEARING —— 元素在容器中显现时需要动画显示。
* (2)CHANGE_APPEARING —— 由于容器中要显现一个新的元素,其它元素的变化需要动画显示。
* (3)DISAPPEARING —— 元素在容器中消失时需要动画显示。
* (4)CHANGE_DISAPPEARING —— 由于容器中某个元素要消失,其它元素的变化需要动画显示。
*/
public class LayoutAnimatorFragment extends Fragment implements OnClickListener{
private Button mButtonAdd;
private Button mButtonReset;
private GridLayout mGridLayout;
private int buttonNumbers = 1;
private LayoutTransition mLayoutTransition;
@Override
public void onActivityCreated(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onActivityCreated(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
View rootView = inflater.inflate(R.layout.fragment_layoutanimator, container, false);
initViews(rootView);
return rootView;
}
public void initViews(View rootView){
mButtonAdd = (Button)rootView.findViewById(R.id.layout_animator_addbutton);
mButtonAdd.setOnClickListener(this);
mButtonReset = (Button)rootView.findViewById(R.id.layout_animator_resetbutton);
mButtonReset.setOnClickListener(this);
mGridLayout = (GridLayout)rootView.findViewById(R.id.layout_animator_gridview);
mLayoutTransition = new LayoutTransition();
//为GridLayout设置mLayoutTransition对象
mGridLayout.setLayoutTransition(mLayoutTransition);
mLayoutTransition.setStagger(LayoutTransition.CHANGE_APPEARING, 30);
mLayoutTransition.setStagger(LayoutTransition.CHANGE_DISAPPEARING, 30);
//设置每个动画持续的时间
mLayoutTransition.setDuration(300);
//初始化自定义的动画效果
customLayoutTransition();
}
@Override
public void onPause() {
// TODO Auto-generated method stub
super.onPause();
}
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
switch (v.getId()) {
case R.id.layout_animator_addbutton:
addButton();
break;
case R.id.layout_animator_resetbutton:
resetButton();
break;
default:
break;
}
}
/**
* 增加Button
*/
public void addButton(){
Button mButton = new Button(getActivity());
LinearLayout.LayoutParams mLayoutParams = new LinearLayout.LayoutParams(50, 50);
mButton.setLayoutParams(mLayoutParams);
mButton.setText(String.valueOf(buttonNumbers++));
mButton.setTextColor(Color.rgb(0, 0, 0));
if(buttonNumbers % 2 == 1){
mButton.setBackgroundColor(Color.rgb(45, 118, 87));
}else{
mButton.setBackgroundColor(Color.rgb(225, 24, 0));
}
mButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
mGridLayout.removeView(v);
}
});
mGridLayout.addView(mButton, Math.min(1, mGridLayout.getChildCount()));
}
/**
* 删除所有的Button,重置GridLayout
*/
public void resetButton(){
mGridLayout.removeAllViews();
buttonNumbers = 1;
}
public void customLayoutTransition(){
/**
* Add Button
* LayoutTransition.APPEARING
* 增加一个Button时,设置该Button的动画效果
*/
ObjectAnimator mAnimatorAppearing = ObjectAnimator.ofFloat(null, "rotationY", 90.0f,0.0f)
.setDuration(mLayoutTransition.getDuration(LayoutTransition.APPEARING));
//为LayoutTransition设置动画及动画类型
mLayoutTransition.setAnimator(LayoutTransition.APPEARING, mAnimatorAppearing);
mAnimatorAppearing.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
// TODO Auto-generated method stub
super.onAnimationEnd(animation);
View view = (View) ((ObjectAnimator) animation).getTarget();
view.setRotationY(0.0f);
}
});
/**
* Add Button
* LayoutTransition.CHANGE_APPEARING
* 当增加一个Button时,设置其他Button的动画效果
*/
PropertyValuesHolder pvhLeft =
PropertyValuesHolder.ofInt("left", 0, 1);
PropertyValuesHolder pvhTop =
PropertyValuesHolder.ofInt("top", 0, 1);
PropertyValuesHolder pvhRight =
PropertyValuesHolder.ofInt("right", 0, 1);
PropertyValuesHolder pvhBottom =
PropertyValuesHolder.ofInt("bottom", 0, 1);
PropertyValuesHolder mHolderScaleX = PropertyValuesHolder.ofFloat("scaleX", 1.0f,0.0f,1.0f);
PropertyValuesHolder mHolderScaleY = PropertyValuesHolder.ofFloat("scaleY", 1.0f,0.0f,1.0f);
ObjectAnimator mObjectAnimatorChangeAppearing = ObjectAnimator.ofPropertyValuesHolder(this, pvhLeft,
pvhTop,pvhRight,pvhBottom,mHolderScaleX,mHolderScaleY).setDuration(mLayoutTransition
.getDuration(LayoutTransition.CHANGE_APPEARING));
mLayoutTransition.setAnimator(LayoutTransition.CHANGE_APPEARING, mObjectAnimatorChangeAppearing);
mObjectAnimatorChangeAppearing.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
// TODO Auto-generated method stub
super.onAnimationEnd(animation);
View view = (View) ((ObjectAnimator) animation).getTarget();
view.setScaleX(1f);
view.setScaleY(1f);
}
});
/**
* Delete Button
* LayoutTransition.DISAPPEARING
* 当删除一个Button时,设置该Button的动画效果
*/
ObjectAnimator mObjectAnimatorDisAppearing = ObjectAnimator.ofFloat(null, "rotationX", 0.0f,90.0f)
.setDuration(mLayoutTransition.getDuration(LayoutTransition.DISAPPEARING));
mLayoutTransition.setAnimator(LayoutTransition.DISAPPEARING, mObjectAnimatorDisAppearing);
mObjectAnimatorDisAppearing.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
// TODO Auto-generated method stub
super.onAnimationEnd(animation);
View view = (View) ((ObjectAnimator) animation).getTarget();
view.setRotationX(0.0f);
}
});
/**
* Delete Button
* LayoutTransition.CHANGE_DISAPPEARING
* 当删除一个Button时,设置其它Button的动画效果
*/
//Keyframe 对象中包含了一个时间/属性值的键值对,用于定义某个时刻的动画状态。
Keyframe mKeyframeStart = Keyframe.ofFloat(0.0f, 0.0f);
Keyframe mKeyframeMiddle = Keyframe.ofFloat(0.5f, 180.0f);
Keyframe mKeyframeEndBefore = Keyframe.ofFloat(0.999f, 360.0f);
Keyframe mKeyframeEnd = Keyframe.ofFloat(1.0f, 0.0f);
PropertyValuesHolder mPropertyValuesHolder = PropertyValuesHolder.ofKeyframe("rotation",
mKeyframeStart,mKeyframeMiddle,mKeyframeEndBefore,mKeyframeEnd);
ObjectAnimator mObjectAnimatorChangeDisAppearing = ObjectAnimator.ofPropertyValuesHolder(this, pvhLeft,pvhTop,pvhRight,pvhBottom,mPropertyValuesHolder)
.setDuration(mLayoutTransition.getDuration(LayoutTransition.CHANGE_DISAPPEARING));
mLayoutTransition.setAnimator(LayoutTransition.CHANGE_DISAPPEARING, mObjectAnimatorChangeDisAppearing);
mObjectAnimatorChangeDisAppearing.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
// TODO Auto-generated method stub
super.onAnimationEnd(animation);
View view = (View) ((ObjectAnimator) animation).getTarget();
view.setRotation(0.0f);
}
});
}
}
LayoutAnimatorFragment的界面布局fragment_layoutanimator.xml代码如下:
[html] view
plaincopy
<LinearLayout 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:background="@color/view_animation_background"
android:orientation="vertical"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
>
<Button
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:text="Add Button"
android:id="@+id/layout_animator_addbutton"
/>
<Button
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:text="Reset Button"
android:id="@+id/layout_animator_resetbutton"
/>
</LinearLayout>
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<GridLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:columnCount="5"
android:animateLayoutChanges="true"
android:id="@+id/layout_animator_gridview"
/>
</ScrollView>
</LinearLayout>
布局界面比较简单,唯一要注意的是GridLayout布局中的android:animateLayoutChanges属性,该属性的值为true或false,true代表当前Layout的布局发生改变时使用动画效果,false则不使用。
最后我们运行程序,看一下运行及操作效果图:
小伙伴们,有没感觉上面的动画效果比较炫,哈哈,想要实现的伙伴们赶紧动手吧!
源代码下载,请戳下面:
GITHUB下载
CSDN下载
相关文章推荐
- Android中添加监听回调接口的方法
- android中horizontal和vertical的区别
- android sdk 文件目录含义介绍
- Android之TextView
- Android Studio配置三 gradle项目构建
- Android Studio配置 二
- Android Studio配置 一
- 第五周Android学习笔记
- Android 登录界面设计
- Android - TextView Ellipsize属性
- android studio导入背景图片,改变图标,定时退出三个操作
- Android图片加载框架Picasso最全使用教程 四
- 随了Android的大流,站入Google阵营,持续更新中......
- Android图片加载框架Picasso最全使用教程 三
- Android四种常见设计模式说明
- Android动画三:属性动画 (property animation)
- Android蓝牙串口通信模板及demo,trick
- Android中Intent传递类对象的方法一(Serializable)
- Android学习之界面篇(二)Android AnimationSet简单使用
- Android框架设计模式(四)——Adapter Method