关于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);

    }

就算是在做定时刷新,不会看到控件总是从原点再次运行到目标位置了。

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