原理
  这种效果是通过自定义控件的方式来实现的,我自定义了一个控件类型,这个自定义控件(PullDownDumperLayout)继承自线性布局(LinearLayout)。
  用户可以下拉弹出的那个视图,例如微信的小程序列表,开发者只是将这个视图移出了父元素之外,所以不可见,我们暂且称之为隐藏头部,只有下拉到一定程度才会弹出,而主体,例如微信的联系人列表,则是可见的,布局见下图。

实现这个效果需要我们做三件工作:

隐藏作为头部的控件
监听用户对屏幕的操作事件
实现下拉回弹的动画效果
  我们这个自定义控件会自动获取内部第一个子元素充当头部,其余的元素则是充当可见的主体(详见代码中的注释)。
  基本的布局原理差不多就这样了,但是我们还需要让自定义控件监听用户的手势操作,例如上下滑动等。这里我和灵感来源的那篇博客一样,让自定义控件实现View.OnTouchListener接口,实现内部的onTouch方法可以监听来自屏幕的所有触摸操作。代码中我让头部和第二个子元素(可见的主体)注册了这个监听器,这是为了方便读者理解,读者可根据自己的需求进行修改。
  注意,对于不能监听屏幕触摸事件的控件需要添加:
    android:clickable="true"
  至此,我们已经可以进行布局和监听用户手势了,但是还需要实现一个头部展开和隐藏的动画效果。当用户将隐藏头部下拉或上滑到一定高度时,这个效果就会被触发,这需要依赖上面所述的onTouch方法。动画效果的实现需要另开一个线程进行操作,线程的启动方式我们可以采用继承AsyncTask类来实现。
  除此之外,我们可能会多次复用这个控件,所以在自定义控件类的最后还需要一些调整参数的set方法。
  这里提个醒,在接下来的代码中,我们的自定义控件因为继承自LinearLayout,里面需要重写onLayout方法,而onLayout方法顾名思义就是布局,这个方法在Activity中的onCreate方法执行之后才会被调用,所以我们可以在Activity的onCreate方法中利用findViewById获取实例,调用上面提到的set方法进行参数的初始化。
  LinearLayout中不止onLayout一个方法,详细解析请读者移步其他关于XML标签加载过程的文章,这里不做赘述。

代码
PullDownDumperLayout .java:

public class PullDownDumperLayout extends LinearLayout implements View.OnTouchListener {

/**
* 取布局中的第一个子元素为下拉隐藏头部
*/
private View mHeadLayout;

/**
* 隐藏头部布局的高的负值
*/
private int mHeadLayoutHeight;

/**
* 隐藏头部的布局参数
*/
private MarginLayoutParams mHeadLayoutParams;

/**
* 判断是否为第一次初始化,第一次初始化需要把headView移出界面外
*/
private boolean mOnLayoutIsInit=false;

/**
* 移动时,前一个坐标
*/
private float mMoveY;

/**
* 如果为false,会退出头部展开或隐藏动画
*/
private boolean mChangeHeadLayoutTopMargin;

/**
* 触发动画的分界线,由mRatio计算得到
*/
private int mBoundary;

/**
* 头部布局的隐藏和展开速度,以及单次执行时间
*/
private int mHeadLayoutHideSpeed;
private int mHeadLayoutUnfoldSpeed;
private long mSleepTime;

/**
* 触发动画的分界线,头部布局上半部分和整体高度的比例
*/
private double mRatio;

public PullDownDumperLayout(Context context, AttributeSet attrs) {
super(context, attrs);
//初始化参数,根据自己的需求调整
mHeadLayoutHideSpeed=-20;
mHeadLayoutUnfoldSpeed=20;
mSleepTime=10;
mRatio=0.5;
}

/**
* 布局开始设置每一个控件
* 在activity的onCreate执行之后才会执行
* 因此可以在onCreate中调用set方法设置参数
*/
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
if(!mOnLayoutIsInit && changed) {
//将第一个子元素作为头部移出界面外
mHeadLayout = this.getChildAt(0);
mHeadLayoutHeight=-mHeadLayout.getHeight();
mBoundary=(int)(mRatio*mHeadLayoutHeight);//计算触发动画分界线
mHeadLayoutParams=(MarginLayoutParams) mHeadLayout.getLayoutParams();
mHeadLayoutParams.topMargin=mHeadLayoutHeight;
mHeadLayout.setLayoutParams(mHeadLayoutParams);
//TODO 设置手势监听器,不能触碰的控件需要添加android:clickable="true"
getChildAt(1).setOnTouchListener(this);
mHeadLayout.setOnTouchListener(this);
//标记已被初始化
mOnLayoutIsInit=true;
}
}

/**
* 屏幕触摸操作监听器
* @return false则注册本监听器的控件将不会对事件做出响应,true则相反
*/
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mMoveY=event.getRawY();//捕获按下时的坐标,初始化mMoveY
mChangeHeadLayoutTopMargin=false;
break;
case MotionEvent.ACTION_MOVE:
float currY=event.getRawY();
int vector=(int)(currY-mMoveY);//向量,用于判断手势的上滑和下滑
mMoveY=currY;
//判断是否为滑动
if(Math.abs(vector)==0){
return false;
}
//头部完全隐藏时不再向上滑动
if (vector < 0 && mHeadLayoutParams.topMargin <= mHeadLayoutHeight) {
return false;
}
//头部完全展开时不再向下滑动
if (vector > 0 && mHeadLayoutParams.topMargin >= 0) {
return false;
}

//对增量进行修正,对滑动距离进行减半
int topMargin = mHeadLayoutParams.topMargin + (vector/2);//阻尼值
if(topMargin>0){
// 瞬间拉动的距离超过了头部高度,因为这一瞬间很短,这里采用直接赋值的方式
// 如需平滑过渡,要另开线程,并且监听到ACTION_DOWN时线程可被打断
topMargin = 0;
}
else if(topMargin<mHeadLayoutHeight){
// 瞬间拉动的距离超过了头部高度,因为这一瞬间很短,这里采用直接赋值的方式
// 如需平滑过渡,要另开线程,并且监听ACTION_DOWN时线程可被打断
topMargin = mHeadLayoutHeight;
}
//用户对屏幕的滑动将会改变控件的TopMargin
mHeadLayoutParams.topMargin = topMargin ;
mHeadLayout.setLayoutParams(mHeadLayoutParams);
break;
default:
//TODO 出现其他触碰事件,如MotionEvent.ACTION_UP时,根据阈值判断此时头部应该弹出还是隐藏
mChangeHeadLayoutTopMargin=true;
if(mHeadLayoutParams.topMargin<=mBoundary){
//隐藏
new MoveHeaderTask().execute(true);
}
else{
//展开
new MoveHeaderTask().execute(false);
}
break;
}
return false;
}

/**
* 新线程,隐藏或者展开头部布局,线程可被ACTION_DOWN打断
*/
class MoveHeaderTask extends AsyncTask<Boolean, Integer, Integer> {

/**
*
* @param opt true为隐藏动画,false为展开动画
* @return
*/
@Override
protected Integer doInBackground(Boolean... opt) {
int topMargin=mHeadLayoutParams.topMargin;
//true为隐藏,false为展开
int speed=(opt[0])?mHeadLayoutHideSpeed:mHeadLayoutUnfoldSpeed;
while(mChangeHeadLayoutTopMargin){
topMargin += speed;
if (topMargin <= mHeadLayoutHeight||topMargin>=0) {
topMargin=(opt[0])?mHeadLayoutHeight:0;
publishProgress(topMargin);
break;
}
publishProgress(topMargin);
sleep(mSleepTime);
}
return null;
}

//调用publishProgress后会执行
@Override
protected void onProgressUpdate(Integer... topMargin) {
mHeadLayoutParams.topMargin=topMargin[0];
mHeadLayout.setLayoutParams(mHeadLayoutParams);
}

}

//调整参数
public void setHeadLayoutHideSpeed(int speed){
this.mHeadLayoutHideSpeed=speed;
}
public void setHeadLayoutUnfoldSpeed(int speed){
this.mHeadLayoutUnfoldSpeed=speed;
}
public void setSleepTime(long time){
this.mSleepTime=time;
}
public void setRatio(double ratio){
this.mRatio=ratio;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">

<com.example.pulldowndumpertest.PullDownDumperLayout
android:tag="记得将这个标签修改为自己的包名"
android:id="@+id/PullDownDumper"
android:layout_width="900px"
android:layout_height="1920px"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:background="@null"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="500px"
android:orientation="vertical"
android:background="@color/colorPrimary"
android:clickable="true">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="隐藏头部"
android:textSize="100px"
android:gravity="center"
android:textColor="#FFFFFF"
android:background="@null"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="1700px"
android:background="@color/colorPrimaryDark"
android:clickable="true">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="可见主体"
android:textSize="100px"
android:gravity="center"
android:textColor="#FFFFFF"
android:background="@null"/>
</LinearLayout>
</com.example.pulldowndumpertest.PullDownDumperLayout>

</android.support.constraint.ConstraintLayout>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
MainActivity.java:

public class MainActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

//TODO 读者可在这里初始化参数
PullDownDumperLayout pddl=findViewById(R.id.PullDownDumper);

}
}
1
2
3
4
5
6
7
8
9
10
11
下面是笔者正在使用的自定义控件,比上述的控件多了一个效果:
  头部处于隐藏或展开的不同状态时,触发动画效果的分界线可以随状态不同而改变。
  还是拿最新版的微信小程序入口来讲,用户在下拉时,小程序界面会占用整个屏幕,如果触发动画的分界线太低,这样导致的结果是用户可能无法通过上滑重新返回联系人列表,但由于微信没有对滑动距离进行减半处理,所以不存在上述问题,可能是出于防止误触的原因,从小程序界面返回联系人列表的方式改用点击底部的一个按钮。而我的控件可以通过改变触发动画效果的分界线来解决这一问题,感兴趣的读者可以研究一下。

public class PullDownDumperLayout extends LinearLayout implements View.OnTouchListener {

/**
* 取布局中的第一个子元素为下拉隐藏头部
*/
private View mHeadLayout;

/**
* 隐藏头部布局的高的负值
*/
private int mHeadLayoutHeight;

/**
* 隐藏头部的布局参数
*/
private MarginLayoutParams mHeadLayoutParams;

/**
* 判断是否为第一次初始化,第一次初始化需要把headView移出界面外
*/
private boolean mOnLayoutIsInit=false;

/**
* 从配置获取的滚动判断阈值,为两点间的距离,超过此阈值判断为滚动
*/
// private int mScaledTouchSlop;

/**
* 按下时的y轴坐标
*/
// private float mDownY;

/**
* 移动时,前一个坐标
*/
private float mMoveY;

/**
* 如果为false,会退出头部展开或隐藏动画
*/
private boolean mChangeHeadLayoutTopMargin;

/**
* 头部布局的隐藏和展开速度,以及单次执行时间
*/
private int mHeadLayoutHideSpeed;
private int mHeadLayoutUnfoldSpeed;
private long mSleepTime;

/**
* 初始化头部布局的偏移值,数值越大,头部可见部分越多,预设值为0,即初始时头部完全不可见
*/
private int mTopMarginOffset;

/**
* 触发动画的分界线,头部布局上半部分和整体高度的比例
*/
private double mUnfoldRatio;
private double mHideRatio;

/**
* 触发动画的分界线,初始值由mRatio计算得到
* 头部处于隐藏时等于mUnfoldBoundary
* 头部处于展开时等于mHideBoundary
* mBoundary在onTouch的ACTION_DOWN中变化
*/
private int mBoundary;
private int mUnfoldBoundary;
private int mHideBoundary;

/**
* 阻尼值,越大越难拖动,呈线性趋势
*/
private int mDumper;

public PullDownDumperLayout(Context context, AttributeSet attrs) {
super(context, attrs);
// mScaledTouchSlop= ViewConfiguration.get(context).getScaledTouchSlop();
mHeadLayoutHideSpeed=-30;
mHeadLayoutUnfoldSpeed=30;
mSleepTime=10;
mUnfoldRatio=0.6;
mHideRatio=mUnfoldRatio;
mDumper=2;
mTopMarginOffset=-200;
}

/**
* 布局开始设置每一个控件
* 在activity的onCreate执行之后才会执行
* 因此可以在onCreate中调用set方法设置参数
*/
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
//只初始化一次
if(!mOnLayoutIsInit && changed) {
//将第一个子元素作为头部移出界面外
mHeadLayout = this.getChildAt(0);
mHeadLayoutHeight=-mHeadLayout.getHeight();
mUnfoldBoundary=(int)(mUnfoldRatio*mHeadLayoutHeight);//计算触发展开动画分界线
mHideBoundary=(int)(mHideRatio*mHeadLayoutHeight);//计算触发隐藏动画分界线
mBoundary=mUnfoldBoundary;//触发动画的分界线初始为mUnfoldBoundary
mHeadLayoutHeight-=mTopMarginOffset;//头部隐藏布局可见的部分
mHeadLayoutParams=(MarginLayoutParams) mHeadLayout.getLayoutParams();
mHeadLayoutParams.topMargin=mHeadLayoutHeight;
mHeadLayout.setLayoutParams(mHeadLayoutParams);
//TODO 设置手势监听器,不能触碰的控件需要添加android:clickable="true"
getChildAt(1).setOnTouchListener(this);
mHeadLayout.setOnTouchListener(this);
//标记已被初始化
mOnLayoutIsInit=true;
}
}

/**
* 屏幕触摸操作监听器
* @return false: 注册本监听器的控件将不会对事件做出响应,true则相反
*/
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
//根据此时处于完全展开或完全隐藏决定mBoundary的值,如果两种情况都不满足则不做改变
if(mHeadLayoutParams.topMargin==mHeadLayoutHeight)
mBoundary=mUnfoldBoundary;
else if(mHeadLayoutParams.topMargin==0)
mBoundary=mHideBoundary;

// mDownY=event.getRawY();//获取按下的屏幕y坐标
mMoveY=event.getRawY();
mChangeHeadLayoutTopMargin=false;//false会打断隐藏或展开头部布局的动画
break;
case MotionEvent.ACTION_MOVE:
float currY=event.getRawY();
int vector=(int)(currY-mMoveY);//向量,用于判断手势的上滑和下滑
mMoveY=currY;
//判断是否为滑动
if(Math.abs(vector)==0){
return false;
}
//头部完全隐藏时不再向上滑动
if (vector < 0 && mHeadLayoutParams.topMargin <= mHeadLayoutHeight) {
return false;
}
//头部完全展开时不再向下滑动
else if (vector > 0 && mHeadLayoutParams.topMargin >= 0) {
return false;
}

//对增量进行修正
int topMargin = mHeadLayoutParams.topMargin + (vector/mDumper);
if(topMargin>0){
// 瞬间拉动的距离超过了头部高度,因为这一瞬间很短,这里采用直接赋值的方式
// 如需实现平滑过渡,要另开线程,并且监听到ACTION_DOWN时线程可被打断
topMargin = 0;
}
else if(topMargin<mHeadLayoutHeight){
// 瞬间拉动的距离超过了头部高度,因为这一瞬间很短,这里采用直接赋值的方式
// 如需实现平滑过渡,要另开线程,并且监听ACTION_DOWN时线程可被打断
topMargin = mHeadLayoutHeight;
}

//使参数生效
mHeadLayoutParams.topMargin = topMargin ;
mHeadLayout.setLayoutParams(mHeadLayoutParams);
break;
default:
//出现其他触碰事件,如MotionEvent.ACTION_UP时,根据阈值mBoundary判断此时头部应该弹出还是隐藏
mChangeHeadLayoutTopMargin=true;//允许执行动画
if(mHeadLayoutParams.topMargin<=mBoundary){
//隐藏
new MoveHeaderTask().execute(true);
}
else{
//展开
new MoveHeaderTask().execute(false);
}
break;
}
return false;
}

/**
* 新线程,隐藏或者展开头部布局,线程可被ACTION_DOWN打断
*/
private class MoveHeaderTask extends AsyncTask<Boolean, Integer, Integer> {

/**
*
* @param opt true为隐藏动画,false为展开动画
* @return
*/
@Override
protected Integer doInBackground(Boolean... opt) {
int topMargin=mHeadLayoutParams.topMargin;
//true为隐藏,false为展开
int speed=(opt[0])?mHeadLayoutHideSpeed:mHeadLayoutUnfoldSpeed;
while(mChangeHeadLayoutTopMargin){
topMargin += speed;
if (topMargin <= mHeadLayoutHeight||topMargin>=0) {
topMargin=(opt[0])?mHeadLayoutHeight:0;
publishProgress(topMargin);
break;
}
publishProgress(topMargin);
sleep(mSleepTime);
}
return null;
}

//调用publishProgress后会执行
@Override
protected void onProgressUpdate(Integer... topMargin) {
mHeadLayoutParams.topMargin=topMargin[0];
mHeadLayout.setLayoutParams(mHeadLayoutParams);
}

}

//调整参数
public void setHeadLayoutHideSpeed(int speed){
this.mHeadLayoutHideSpeed=speed;
}
public void setHeadLayoutUnfoldSpeed(int speed){
this.mHeadLayoutUnfoldSpeed=speed;
}
public void setSleepTime(long time){
this.mSleepTime=time;
}
public void setDumper(int dumper){
this.mDumper=dumper;
}
public void setTopMarginOffset(int offset){
this.mTopMarginOffset=-offset;
}

/**
* 头部处于隐藏状态时,触发展开动画的分界线
* @param ratio 头部布局上部分与下部分的分界线
*/
public void setUnfoldRatio(double ratio){
this.mUnfoldRatio=ratio;
}

/**
* 头部处于展开状态时,触发隐藏动画的分界线
* @param ratio 头部布局上部分与下部分的分界线
*/
public void setHideRatio(double ratio){
this.mHideRatio=ratio;
}
}```

---------------------

Android安卓下拉阻尼效果实现原理及简单实例的更多相关文章

  1. Android PullToRefresh下拉刷新控件的简单使用

    PullToRefresh这个开源库早就听说了,不过一直没用过.作为一个经典的的开源库,我觉得还是有必要认识一下. 打开github上的网址:https://github.com/chrisbanes ...

  2. Android仿苹果版QQ下拉刷新实现(一) ——打造简单平滑的通用下拉刷新控件

    前言: 忙完了结婚乐APP的开发,终于可以花一定的时间放在博客上了.好了,废话不多说,今天我们要带来的效果是苹果版本的QQ下拉刷新.首先看一下目标效果以及demo效果:      因为此效果实现的步骤 ...

  3. Xamarin. Android实现下拉刷新功能

    PS:发现文章被其他网站或者博客抓取后发表为原创了,给图片加了个水印 下拉刷新功能在安卓和iOS中非常常见,一般实现这样的功能都是直接使用第三方的库,网上能找到很多这样的开源库.然而在Xamarin. ...

  4. Android实现下拉导航选择菜单效果

    本文介绍在Android中如何实现下拉导航选择菜单效果.   关于下拉导航选择菜单效果在新闻客户端中用的比较多,当然也可以用在其他的项目中,这样可以很方便的选择更多的菜单.我们可以让我们的应用顶部有左 ...

  5. Android智能下拉刷新加载框架—看这些就够了

    一些值得学习的几个下拉刷新上拉加载开源库 Android智能下拉刷新框架-SmartRefreshLayout 支持所有的 View(AbsListView.RecyclerView.WebView. ...

  6. html5实现移动端下拉刷新(原理和代码)

    这篇文章给大家介绍的内容是关于html5实现移动端下拉刷新(原理和代码),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助. 移动端的下拉刷新是一个很常见的功能,也有许多开源库实现了这个功 ...

  7. android一个下拉放大库bug的解决过程及思考

    android一个下拉放大库bug的解决过程及思考 起因 项目中要做一个下拉缩放图片的效果,搜索了下github上面,找到了两个方案. https://github.com/Frank-Zhu/Pul ...

  8. Win Socket编程原理及简单实例

    [转]http://www.cnblogs.com/tornadomeet/archive/2012/04/11/2442140.html 使用Linux Socket做了小型的分布式,如Linux ...

  9. android官方下拉刷新控件SwipeRefreshLayout的使用

    可能开发安卓的人大多数都用过很多下拉刷新的开源组件,但是今天用了官方v4支持包的SwipeRefreshLayout觉得效果也蛮不错的,特拿出来分享. 简介:SwipeRefreshLayout组件只 ...

随机推荐

  1. java -- 虚拟机和内存

    从大方向来分:栈内存,堆内存,方法区,本地方法栈,程序计数器 java从存储数据的角度来分: 寄存器(register):最快的存储区,由编译器根据需求进行分配,不由认为控制. 堆栈(statck): ...

  2. Burpsuite实验(二)

    一.这次我们使用一下burpsuite的代理拦截功能. 图中的proxy是代理的选项,其中intercept是拦截的功能,在浏览器中请求的包,都经过它. 这是打开拦截时候的状态.forward是通过此 ...

  3. JAVA 集合JGL

    集合 Java提供了四种类型的“集合类”:Vector(矢量).BitSet(位集).Stack(堆栈)以及Hashtable(散列表).与拥有集合功能的其他语言相比,尽管这儿的数量显得相当少,但仍然 ...

  4. ASP.NET Core MVC 2.x 全面教程_ASP.NET Core MVC 13. 安装前端库

    前端库使用npm进行安装,需要先建立webpack.json文件 因为我们没有使用npm安装任何库,所以npm的文件夹是空的 这里是用于开发时构建时引用的库写在这里 这里用到bootStrap 开发时 ...

  5. hdu5443 【线段树】

    题意: 略 思路: 暴力是可以的O(1e7),这里采用线段树,线段树区间查找O(logn) #include<stdio.h> #include<string.h> #incl ...

  6. P5167 xtq的神笔

    传送门 题解 倍增也好二分也好,果然复杂度只要和\(\log\)插上关系就没我啥事了-- 首先由一个显而易见然而我完全没有发现的结论,设\(calc(l,r)\)表示区间\([l,r]\)的\(or\ ...

  7. UWP 动画

    一:StoryBoard 一般翻译成演示图版或者故事板,就像电影中的情节串联板,它是一个动画时间线的容器. 二:动画的分类       简单动画:以Animation结尾,例如DoubleAnimat ...

  8. 【loj6034】「雅礼集训 2017 Day2」线段游戏

    #6034. 「雅礼集训 2017 Day2」线段游戏 内存限制:256 MiB 时间限制:1000 ms 标准输入输出 题目类型:传统 评测方式:Special Judge 上传者: 匿名 题目描述 ...

  9. Jury Meeting CodeForces - 854D

    Jury Meeting CodeForces - 854D 思路:暴力枚举会议开始的那一天(只需用所有向0点飞的航班的那一天+1去枚举即可),并计算所有人此情况下去0点和从0点出来的最小花费. 具体 ...

  10. RHEL6.5---LVS(IP-TUN)

    实验环境: 主机名 IP  所需软件 master eth0==>192.168.30.160(RIP) eth0:1==>192.168.30.130(VIP) ipvsadm node ...