關於View的移動問題

1. 背景:快端午節了,運營想搞個活動,根據用戶交互次數的多少,讓龍舟來划動。

需求圖如下:
在這裏插入圖片描述
在此界面,每隔15s就要發一起請求,從而來更新龍舟的位置。
涉及到的技術點就是:view座標的移動。

2.實現:

先說走過的彎路:

  1. getLeft拿到的座標爲0的問題:
    這個很常見,因爲獲取時機不對,view 還沒佈置好,這個時候去拿座標是拿不到的。
    具體怎麼獲取,可以參考:此處
    我是在onWindowFocusChanged中拿到了5條龍舟各自的onLeft值,而不再是0了。
  2. 控件的移動問題:
    最初開始用的是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);

    }

就算是在做定時刷新,不會看到控件總是從原點再次運行到目標位置了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章