首先定义布局代码,这个可以i是安卓的任意控件,如:
<LinearLayout
android:id="@+id/ll_push_register_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_gravity="center_horizontal">
<android.support.v7.widget.AppCompatImageView
android:layout_width="29dp"
android:layout_height="29dp"
android:layout_gravity="center_vertical"
android:scaleType="fitXY"
android:src="@drawable/ic_down_push"/>
<android.support.v7.widget.AppCompatTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="下拉展开签到"
android:layout_gravity="center_vertical"
android:gravity="center_vertical"
android:textSize="13sp"
android:textColor="@color/white"/>
</LinearLayout>
下面是更改控件Y坐标的核心代码:
mPushRegisterLayout.postDelayed(new Runnable() { //等界面绘制完成后启动动画
@Override
public void run() {
mPushRegisterLayout.setTag(R.string.isUp,false);
mStartPosition = new Point((int)mPushRegisterLayout.getX(), (int) mPushRegisterLayout.getY());
mHandler.sendEmptyMessageDelayed(START_PUSH_ANIMATION,1500);
}
},1000);
通过View的postDelayed()),开启一个子线程去延时发送一个消息去更改控件的Y坐标,更改位移坐标的代码如下:
/**
* 设置偏移
*/
private void setPushToRegisterOffSet() {
//水滴初始的位置
float original = mStartPosition.y;
float step = 0.6f;
boolean isUp = (boolean) mPushRegisterLayout.getTag(R.string.isUp);
float translationY;
//根据水滴tag中的上下移动标识移动view
if (isUp) {
translationY = mPushRegisterLayout.getY() - step;
} else {
translationY = mPushRegisterLayout.getY() + step;
}
//对水滴位移范围的控制
if (translationY - original > CHANGE_RANGE) {
translationY = original + CHANGE_RANGE;
mPushRegisterLayout.setTag(R.string.isUp, true);
} else if (translationY - original < -CHANGE_RANGE) {
translationY = original - CHANGE_RANGE;
// FIXME:每次当水滴回到初始点时再一次设置水滴的速度,从而达到时而快时而慢
mPushRegisterLayout.setTag(R.string.isUp, false);
}
mPushRegisterLayout.setY(translationY);
}
因为安卓定义不能在子线程更改UI,所以我们使用安卓原生的Handler实现从子线程回到主线程来更UI界面,为什么要开启子线程去延时发送Handler处理的消息体呢?
因为根据android的OpenGl渲染界面需要1秒钟的时间,所以需要先让界面先渲染显示出来之后,再获取到控件的Y轴坐标值保存到一个Point里面,当然这个可以优化一下数据结构,节省内存的消耗。
/**
* 创建一个Handler,不断发送消息来更新下拉签到动画
* @return
*/
@SuppressLint("HandlerLeak")
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case START_PUSH_ANIMATION:
if(!isAnimation){//标识是否退出,防止界面销毁时,再一次改变UI
isAnimation = false;
return;
}
setPushToRegisterOffSet();
mHandler.sendEmptyMessageDelayed(START_PUSH_ANIMATION, DELAY_MILLIS);
break;
default:
break;
}
}
};```
最后也是比较容易忘记的一步就是在界面不可见的时候,要移除消息回调,不再后台发送消息更改控件位移位置。
mHandler.removeCallbacksAndMessages(this); //对用户不可见的时候,移除消息