Programmatically line up two views at a corner

纵饮孤独 提交于 2019-12-23 06:04:36

问题


So this seems like a very simple question, but I can't figure out how to get the proper location after scaling a view.

I'm trying to line up an imageView to the bottom right corner of another imageView. This code works fine if I don't modify firstImageView.

secondImageView.setX(firstImageView.getRight());
secondImageView.setY(firstImageView.getBottom());

But then after I apply a translation or scale to the firstImageView, the code above doesn't seem to work correctly (doesn't line up at corners). I'm guessing that scaling doesn't affect the actual size of the view, even though it's clearly resized. So how would I go about setting the secondImageView to the bottom right of the firstImageView even after scale, rotation and/or translation have been modified?

EDIT: two views at a corner code

firstImageView.setOnTouchListener(new View.OnTouchListener() {

            float startX, startY;
            float translationX, translationY;
            float startMoveX, startMoveY;



            public boolean onTouch(View v, MotionEvent e) {

                if (e.getAction() == MotionEvent.ACTION_DOWN) {
                    secondImageView.setX(imageView.getRight());
                    secondImageView.setY(imageView.getBottom());
                    secondImageView.setVisibility(View.VISIBLE);

                    startX = e.getRawX();
                    startY = e.getRawY();

                    startMoveX = firstImageView.getX();
                    startMoveY = firstImageView.getY();




                } else if (e.getAction() == MotionEvent.ACTION_MOVE) {

                    translationX = e.getRawX() - startX + startMoveX;
                    translationY = e.getRawY() - startY + startMoveY;
                    firstImageView.setTranslationX(translationX);
                    firstImageView.setTranslationY(translationY);


                    secondImageView.setTranslationX(firstImageView.getX()+firstImageView.getMeasuredWidth());
                    secondImageView.setTranslationY(firstImageView.getY()+firstImageView.getMeasuredHeight());

                } else if (e.getAction() == MotionEvent.ACTION_UP) {

                }
                return true;
            }
        });
    }

scaling code:

secondImageView.setScaleX(2);
secondImageView.setScaleY(2);

回答1:


You are correct in your assumption. Translation does not affect the bounds of the view. However if you calculate the position offset (delta) of the second view from the first at the beginning of the gesture, you can translate both views at once. Here's a working sample that you can use.

activity_test.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:tools="http://schemas.android.com/tools"
  android:layout_width="match_parent"
  android:layout_height="match_parent">

  <ImageView
    android:id="@+id/photo"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentTop="true"
    android:layout_centerHorizontal="false"
    android:layout_marginTop="0dp"
    android:src="@drawable/photo"/>

  <ImageView
    android:id="@+id/photo_two"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignRight="@+id/photo"
    android:layout_alignBottom="@+id/photo"
    android:src="@drawable/ic_launcher"/>

</RelativeLayout>

TestActivity.java

public class TestActivity extends Activity {

  private static String TAG = "TestActivity";
  private ImageView mPhoto;
  private ImageView mPhotoTwo;
  private float mStartX;
  private float mStartY;
  private float mDeltaX;
  private float mDeltaY;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_test);
    Log.d(TAG, "onCreate");

    mPhoto = (ImageView)findViewById(R.id.photo);
    mPhotoTwo = (ImageView)findViewById(R.id.photo_two);

    mPhoto.setOnTouchListener(new View.OnTouchListener(){
      @Override
      public boolean onTouch(View view, MotionEvent e) {
        boolean result = false;
        int action = e.getAction();

        if(action == MotionEvent.ACTION_DOWN){

          mStartX = e.getX();
          mStartY = e.getY();
          mDeltaX = mPhoto.getWidth() - mPhotoTwo.getWidth();
          mDeltaY = mPhoto.getHeight() - mPhotoTwo.getHeight();
          result = true;

        }else if(action == MotionEvent.ACTION_MOVE){

          float x = e.getX();
          float y = e.getY();
          float deltaX = x - mStartX;
          float deltaY = y - mStartY;

          float viewX = view.getX();
          float viewY = view.getY();
          float valueX = deltaX + viewX;
          float valueY = deltaY + viewY;

          mPhoto.setX(valueX);
          mPhoto.setY(valueY);

          float valueTwoX = valueX + mDeltaX;
          float valueTwoY = valueY + mDeltaY;

          mPhotoTwo.setX(valueTwoX);
          mPhotoTwo.setY(valueTwoY);

          result = true;
        }

        return result;

      }
    });
  }
}

UPDATE

Per request I'm modifying the code to remove all layout_align properties from the layout files. All positioning (including the initial rendering of the view) will be done programatically.

activity_test.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:tools="http://schemas.android.com/tools"
  android:id="@+id/relativelayout"
  android:layout_width="match_parent"
  android:layout_height="match_parent">

  <ImageView
    android:id="@+id/photo"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/photo"/>

  <ImageView
    android:id="@+id/photo_two"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/ic_launcher"/>

</RelativeLayout>

TestActivity.java

public class TestActivity extends Activity {

  private static String TAG = "TestActivity";
  private RelativeLayout mRelativeLayout;
  private ImageView mPhoto;
  private ImageView mPhotoTwo;
  private float mStartX;
  private float mStartY;
  private float mDeltaX;
  private float mDeltaY;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_test);
    Log.d(TAG, "onCreate");

    mRelativeLayout = (RelativeLayout)findViewById(R.id.relativelayout);
    mPhoto = (ImageView)findViewById(R.id.photo);
    mPhotoTwo = (ImageView)findViewById(R.id.photo_two);

    ViewTreeObserver observer = mRelativeLayout.getViewTreeObserver();
    observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
      @Override
      public void onGlobalLayout() {
        float viewX = mPhoto.getX();
        float viewY = mPhoto.getY();

        mDeltaX = mPhoto.getWidth() - mPhotoTwo.getWidth();
        mDeltaY = mPhoto.getHeight() - mPhotoTwo.getHeight();

        float valueTwoX = viewX + mDeltaX;
        float valueTwoY = viewY + mDeltaY;

        mPhotoTwo.setX(valueTwoX);
        mPhotoTwo.setY(valueTwoY);
      }
    });


    mPhoto.setOnTouchListener(new View.OnTouchListener(){
      @Override
      public boolean onTouch(View view, MotionEvent e) {
        boolean result = false;
        int action = e.getAction();

        if(action == MotionEvent.ACTION_DOWN){

          mStartX = e.getX();
          mStartY = e.getY();
          result = true;

        }else if(action == MotionEvent.ACTION_MOVE){

          float x = e.getX();
          float y = e.getY();
          float deltaX = x - mStartX;
          float deltaY = y - mStartY;

          float viewX = view.getX();
          float viewY = view.getY();
          float valueX = deltaX + viewX;
          float valueY = deltaY + viewY;

          mPhoto.setX(valueX);
          mPhoto.setY(valueY);

          float valueTwoX = valueX + mDeltaX;
          float valueTwoY = valueY + mDeltaY;

          mPhotoTwo.setX(valueTwoX);
          mPhotoTwo.setY(valueTwoY);

          result = true;
        }

        return result;

      }
    });
  }
}



回答2:


Initially the layout was drawn using the first image scale. Later on scale changes you need to redraw the layout to effect the changes you made.

on scale change run requestLayout() or invalidate()

findViewById(android.R.id.content).invalidate();

If in the course of processing the event, the view's bounds may need to be changed, the view will call requestLayout().

Similarly, if in the course of processing the event the view's appearance may need to be changed, the view will call invalidate().

If either requestLayout() or invalidate() were called, the framework will take care of measuring, laying out, and drawing the tree as appropriate.



来源:https://stackoverflow.com/questions/23159579/programmatically-line-up-two-views-at-a-corner

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!