1. 背景:快端午節了,運營想搞個活動,根據用戶交互次數的多少,讓龍舟來划動。
需求圖如下:
在此界面,每隔15s就要發一起請求,從而來更新龍舟的位置。
涉及到的技術點就是:view座標的移動。
2.實現:
先說走過的彎路:
- getLeft拿到的座標爲0的問題:
這個很常見,因爲獲取時機不對,view 還沒佈置好,這個時候去拿座標是拿不到的。
具體怎麼獲取,可以參考:此處
我是在onWindowFocusChanged中拿到了5條龍舟各自的onLeft值,而不再是0了。 - 控件的移動問題:
最初開始用的是view.layout(left,top,right,bottom)。
假定的龍舟只能橫向向左移動,只需要計算left值減去要移動的距離,就爲龍舟最終要移動的位置。
//此處是測量view的left值
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
Timber.d("onWindowFocusChanged");
measureBoat();
isMeasured = true;
}
private void measureBoat() {
beginLeftX1 = ivDragon1.getLeft();
beginLeftX2 = ivDragon2.getLeft();
beginLeftX3 = ivDragon3.getLeft();
beginLeftX4 = ivDragon4.getLeft();
beginLeftX5 = ivDragon5.getLeft();
Timber.d("beginLeftX %d, %d,%d,%d,%d", beginLeftX1,beginLeftX2,beginLeftX3, beginLeftX4,beginLeftX5);
}
//此處是計算view要移動的值:boat_1是移動的比率,以此類推各個參數的意義
private void moveBoat(double boat_1, double boat_2, double boat_3, double boat_4,
double boat_5) {
if (!isMeasured) {
Timber.d("還沒有測量");
return;
}
Timber.d("left %d,%d,%d,%d,%d",beginLeftX1 -(int) (CONSTANT_DISATANCE * boat_1),
beginLeftX2-(int) (CONSTANT_DISATANCE * boat_2),
beginLeftX3-(int) (CONSTANT_DISATANCE * boat_3),
beginLeftX4-(int) (CONSTANT_DISATANCE * boat_4),
beginLeftX5-(int) (CONSTANT_DISATANCE * boat_5));
ivDragon1.layout(beginLeftX1-(int) (CONSTANT_DISATANCE * boat_1), ivDragon1.getTop(), ivDragon1.getRight(), ivDragon1.getBottom());
ivDragon2.layout(beginLeftX2 -(int) (CONSTANT_DISATANCE * boat_2), ivDragon2.getTop(), ivDragon2.getRight(), ivDragon2.getBottom());
ivDragon3.layout( beginLeftX3 -(int) (CONSTANT_DISATANCE * boat_3), ivDragon3.getTop(), ivDragon3.getRight(), ivDragon3.getBottom());
ivDragon4.layout(beginLeftX4 -(int) (CONSTANT_DISATANCE * boat_4), ivDragon4.getTop(), ivDragon4.getRight(), ivDragon4.getBottom());
ivDragon5.layout(beginLeftX5 -(int) (CONSTANT_DISATANCE * boat_5), ivDragon5.getTop(), ivDragon5.getRight(), ivDragon5.getBottom());
}
然後奇怪的事件來了,計算移動的數據明明是對的,也是變動的,但是龍舟居然一動不動。
單獨做了一個測試:寫一個按鈕,來調用同樣的方法,看看是否能移動。
測試代碼如下:
@OnClick(R.id.btn_move)
public void onViewClicked() {
ivDragon1.layout(1005, ivDragon1.getTop(), ivDragon1.getRight(), ivDragon1.getBottom());
Timber.d("beginLeftX5 %d", beginLeftX5);
ivDragon2.layout(1274, ivDragon2.getTop(), ivDragon2.getRight(), ivDragon2.getBottom());
ivDragon3.layout(1331, ivDragon3.getTop(), ivDragon3.getRight(), ivDragon3.getBottom());
ivDragon4.layout(1293, ivDragon4.getTop(), ivDragon4.getRight(), ivDragon4.getBottom());
ivDragon5.layout(1235, ivDragon5.getTop(), ivDragon5.getRight(), ivDragon5.getBottom());
}
當我點擊屏幕上這個move button的時候,龍舟是移動的,但是定時調用moveBoat的時候,船隻又回到原處去了,而且還是一動不動。懷疑是layout這裏出了問題。
網上搜索了下,參考此篇文章
照葫蘆畫瓢來改進下:
ivDragon1.postDelayed(new Runnable() {
@Override
public void run() {
ivDragon1.layout(beginLeftX1 -(int) (CONSTANT_DISATANCE * boat_1), ivDragon1.getTop(), ivDragon1.getRight(), ivDragon1.getBottom());
ivDragon2.layout(beginLeftX2 -(int) (CONSTANT_DISATANCE * boat_2), ivDragon2.getTop(), ivDragon2.getRight(), ivDragon2.getBottom());
ivDragon3.layout( beginLeftX3-(int) (CONSTANT_DISATANCE * boat_3), ivDragon3.getTop(), ivDragon3.getRight(), ivDragon3.getBottom());
ivDragon4.layout(beginLeftX4 -(int) (CONSTANT_DISATANCE * boat_4), ivDragon4.getTop(), ivDragon4.getRight(), ivDragon4.getBottom());
ivDragon5.layout(beginLeftX5-(int) (CONSTANT_DISATANCE * boat_5), ivDragon5.getTop(), ivDragon5.getRight(), ivDragon5.getBottom());
}
},100);
結果是:龍舟可以移動了,但是效果特別不好,因爲頁面要定時刷新數據,而每次刷新一次數據,都可以看到控件從原點移動到目標位置,就算控件已經在最新位置了,用戶還是可以感知view從原點再移動到最新位置。這個結果肯定是不敢給產品看的,一定通不過,只能再換個方案移動view了。
換一種方案:
採用layputparams來移動控件。
做完後發現,此方案纔是簡單有效的。
修改如下:
//確定好layoutparams:
private void initLayoutParams() {
params1 = new RelativeLayout.LayoutParams(530, 164);
params1.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM,RelativeLayout.TRUE);
params1.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, RelativeLayout.TRUE);
params1.bottomMargin = 460;
params2 = new RelativeLayout.LayoutParams(530, 164);
params2.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM,RelativeLayout.TRUE);
params2.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, RelativeLayout.TRUE);
params2.bottomMargin = 348;
params3 = new RelativeLayout.LayoutParams(530, 164);
params3.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM,RelativeLayout.TRUE);
params3.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, RelativeLayout.TRUE);
params3.bottomMargin = 236;
params4 = new RelativeLayout.LayoutParams(530, 164);
params4.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM,RelativeLayout.TRUE);
params4.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, RelativeLayout.TRUE);
params4.bottomMargin = 112;
params5 = new RelativeLayout.LayoutParams(530, 164);
params5.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM,RelativeLayout.TRUE);
params5.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, RelativeLayout.TRUE);
params5.bottomMargin = 12;
}
//更新layotparams:主要是rigthMargin的改變,船的位置就改變了
private void moveBoat(double boat_1, double boat_2, double boat_3, double boat_4,
double boat_5) {
params1.rightMargin =(int) (CONSTANT_DISATANCE * boat_1);
ivDragon1.setLayoutParams(params1);
params2.rightMargin =(int) (CONSTANT_DISATANCE * boat_2);
ivDragon2.setLayoutParams(params2);
params3.rightMargin =(int) (CONSTANT_DISATANCE * boat_3);
ivDragon3.setLayoutParams(params3);
params4.rightMargin =(int) (CONSTANT_DISATANCE * boat_4);
ivDragon4.setLayoutParams(params4);
params5.rightMargin =(int) (CONSTANT_DISATANCE * boat_5);
ivDragon5.setLayoutParams(params5);
}
就算是在做定時刷新,不會看到控件總是從原點再次運行到目標位置了。