3

I am trying to make Custom RelativeLayout which can scale and scroll. Right now I have tried to achieve scale. Now I have made the custom Relative layout as parent layout of another relative layout which contains touchable Imageview as its child. Now when I zoom the parent custom relative layout child also gets zoom but the clickable area of the Imageview translates I dont know why ? When Imageview or layout are at normal position the clickable area is on the Imageview but as soon as the layout gets zoom the clickable area shifts ? I do not know why am I facing weird position displacement of clickable

here is the code

my custom relative layourt

public class scaleLayout extends RelativeLayout {

    private float mScaleFactor=1.0f;
      private long lastTouchTime = -1;

    public scaleLayout(Context context)
    {
        super(context);

    //  setWillNotDraw(false);

    }

    public scaleLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        //setWillNotDraw(false);


        // TODO Auto-generated constructor stub
    }


/*  @Override 
    public boolean dispatchTouchEvent(MotionEvent event) { 
                return super.dispatchTouchEvent(event); 
       } */

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        // TODO Auto-generated method stub

        return super.onTouchEvent(event);
    }


    @Override
      public boolean onInterceptTouchEvent(MotionEvent ev) {

        if (ev.getAction() == MotionEvent.ACTION_DOWN) {

          long thisTime = System.currentTimeMillis();
          if (thisTime - lastTouchTime < 250) {

            // Double tap
              mScaleFactor=1.5f;
              invalidate();
            lastTouchTime = -1;

          } else {

            // Too slow :)
            /*  mScaleFactor=1.0f;
              invalidate();*/
            lastTouchTime = thisTime;
          }
        }

        return super.onInterceptTouchEvent(ev);
      }




    @Override
    protected void dispatchDraw(Canvas canvas) {
        // TODO Auto-generated method stub

            canvas.save(Canvas.MATRIX_SAVE_FLAG);
            canvas.scale(mScaleFactor, mScaleFactor);
            super.dispatchDraw(canvas);
            canvas.restore();


    }


    @Override
    public ViewParent invalidateChildInParent(int[] location, Rect dirty) {
        // TODO Auto-generated method stub
        return super.invalidateChildInParent(location, dirty);
    }

    protected void onLayout(boolean changed, int l, int t, int r, int b)
    {
        int count = getChildCount();
        for(int i=0;i<count;i++){
            View child = getChildAt(i); 
            if(child.getVisibility()!=GONE){
                RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams)child.getLayoutParams();
                child.layout(
                    (int)(params.leftMargin * mScaleFactor), 
                    (int)(params.topMargin * mScaleFactor), 
                    (int)((params.leftMargin + child.getMeasuredWidth()) * mScaleFactor), 
                    (int)((params.topMargin + child.getMeasuredHeight()) * mScaleFactor) 
                    );
            }
        }
    }

here is the activity

public class LayoutZoomingActivity extends Activity implements OnTouchListener {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        ImageView img1 = (ImageView) findViewById(R.id.imageView1);
        img1.setOnTouchListener(this);
        ImageView img2 = (ImageView) findViewById(R.id.imageView2);
        img2.setOnTouchListener(this);

    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        // TODO Auto-generated method stub

        ImageView iv= (ImageView) v;
        v.setVisibility(View.INVISIBLE);


        return false;
    }

this is xml

<com.layoutzooming.scaleLayout  xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    >

 <RelativeLayout 
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@drawable/gm01"
    >

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="jhkibnkij"
        android:layout_centerInParent="true"
        android:textColor="#FFFFFF"
        android:textSize="25dp" />

    <ImageView
        android:id="@+id/imageView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/textView1"
        android:layout_marginLeft="500dp"
        android:layout_marginTop="250dp"
        android:background="#000"
        android:src="@drawable/dih01" />

     <ImageView
        android:id="@+id/imageView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/textView1"
        android:layout_marginLeft="350dp"
        android:layout_marginTop="250dp"
        android:background="#000"
        android:src="@drawable/dih02" />

 </RelativeLayout>
</com.layoutzooming.scaleLayout>
user1169079
  • 3,053
  • 5
  • 42
  • 71

2 Answers2

3

Some how I managed to fix this issue by adding the below code in LayoutZoomingActivity .

 public class LayoutZoomingActivity extends Activity implements OnTouchListener {

    ImageView img1;     ImageView img2;     /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        img1 = (ImageView) findViewById(R.id.imageView1);
        img1.setOnTouchListener(this);
        img2 = (ImageView) findViewById(R.id.imageView2);
        img2.setOnTouchListener(this);

    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        // TODO Auto-generated method stub
        Log.d("b","b");
        if(isViewContains(img1, (int)event.getX(), (int)event.getY()))      {
            img1.setVisibility(View.GONE);      }
        if(isViewContains(img2, (int)event.getX(), (int)event.getY()))      {
            img2.setVisibility(View.GONE);      }

        return false;
    }
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        // TODO Auto-generated method stub
        Log.d("onTouchEvent c","c"+(int)event.getX()+","+(int)event.getY());
        if(isViewContains(img1, (int)event.getX(), (int)event.getY()))      {
            img1.setVisibility(View.GONE);
            img1.invalidate();      }
        if(isViewContains(img2, (int)(event.getX()/scaleLayout.mScaleFactor), (int)(event.getY()/scaleLayout.mScaleFactor)))        {
            img2.setVisibility(View.GONE);
            img2.invalidate();      }
        return super.onTouchEvent(event);
    }
    private boolean isViewContains(View view, int rx, int ry) {
        int[] l = new int[2];
        view.getLocationOnScreen(l);
        int x = l[0];
        int y = l[1];
        int w = view.getWidth();
        int h = view.getHeight();
        Log.d("isViewContains::"+x+"::"+y+"::"+w+"::"+h,rx+"::"+ry);
        if (rx < x || rx > x + w || ry < y || ry > y + h) {
            return false;
        }
        return true;
    } }

Can you please try this and customize according to your requirement.

Pavandroid
  • 1,586
  • 2
  • 15
  • 30
  • No need of the Methods onLayout in scaleLayout. – Pavandroid Mar 26 '12 at 12:30
  • Thanks its working but I did not got the logic behind it ? how will it not call onLayout as Parent will always ask child for the onLayout for the child rite ? and may I please get the explanation for above logic .. I am very keen to learn this zooming thing – user1169079 Mar 27 '12 at 09:15
  • Actually onLayout is called only once at the time of creating the Object only. Here in the above logic, I am manually checking the existence of the Views in onTouchEvent(). here the problem is we can zoom the canvas and because of which the placements of current views changed which is not according to the previous X,Y coordinates. So according to Android, It don't know about the new translated coordinates but it know's only the past coordinates. So still working for the past co-ordinates in your code. – Pavandroid Mar 27 '12 at 10:15
  • According to my Code, even i am not using the onTouch method which is not called every time when user touched the Screen.So, I used onTouchEvent. Here i am getting the Raw X and Y coordinates. I am checking whether the point which comes in the onTouchEvent is present in the view and if it presents am doing what ever i want to do. – Pavandroid Mar 27 '12 at 10:30
  • I am calculating the New translated X,Y co-ordinates at if(isViewContains(img2, (int)(event.getX()/scaleLayout.mScaleFactor), (int)(event.getY()/scaleLayout.mScaleFactor))) – Pavandroid Mar 27 '12 at 10:32
  • other than doing every thing in onTouch event, even you can call performClick for that particular View. So what evr you write in the onClickListener, will be called. – Pavandroid Mar 27 '12 at 10:37
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/9367/discussion-between-user1201239-and-pavandroid) – user1169079 Mar 27 '12 at 12:09
  • I Was fool .. maybe I was out of my mind and did not see the changes properly....Thanks man ...you are great !!! I have started chat discussion please do reply if I stuck somewhere..thanks in advance.. – user1169079 Mar 27 '12 at 12:47
0

The actual are of the parent layout(Scalable relative layout) is increased so this relative layout and image view both try to adjust themselves to the same position as it was before increasing .Before scaling they had some position relative to the screen and now after scalling they try to adjust to the same position .Try using Linear layout for scalling

  • So you mean to say try custom LinearLayout as the parent layout ? and inside that RelativeLayout and imageviews? .. – user1169079 Mar 23 '12 at 22:04