Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android Gallery zoom in/out

Hi I am using the Gallery widget to show images downloaded from the internet.

to show several images and I would like to have a gradual zoom while people slide up and down on the screen. I know how to implement the touch event the only thing I don't know how to make the whole gallery view grow gradually. I don't want to zoom in on one image I want the whole gallery to zoom in/out gradually.

EDIT3: I manage to zoom the visible part of the gallery but the problem is I need to find a way for the gallery to find out about it and update it's other children too.

What happens is if 3 images are visible then you start zooming and the gallery does get smaller, so do the images but what I would like in this case is more images to be visible but I don't know how to reach this desired effect. Here's the entire code:

public class Gallery1 extends Activity implements OnTouchListener {

private static final String TAG = "GalleryTest";
private float zoom=0.0f;
// Remember some things for zooming
PointF start = new PointF();
PointF mid = new PointF();
Gallery g;
LinearLayout layout2;
private ImageAdapter ad;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.gallery_1);
    layout2=(LinearLayout) findViewById(R.id.layout2);

    // Reference the Gallery view
    g = (Gallery) findViewById(R.id.gallery);
    // Set the adapter to our custom adapter (below)
    ad=new ImageAdapter(this);
    g.setAdapter(ad);


    layout2.setOnTouchListener(this);

}


public void zoomList(boolean increase) {
    Log.i(TAG, "startig animation");


    AnimatorSet set = new AnimatorSet();
    set.playTogether(

        ObjectAnimator.ofFloat(g, "scaleX", zoom),
        ObjectAnimator.ofFloat(g, "scaleY", zoom)

    );
    set.addListener(new AnimatorListener() {

        @Override
        public void onAnimationStart(Animator animation) {


        }

        @Override
        public void onAnimationRepeat(Animator animation) {
            // TODO Auto-generated method stub

        }

        @Override
        public void onAnimationEnd(Animator animation) {

        }

        @Override
        public void onAnimationCancel(Animator animation) {
            // TODO Auto-generated method stub

        }
    });
    set.setDuration(100).start();


}


public class ImageAdapter extends BaseAdapter {
    private static final int ITEM_WIDTH = 136;
    private static final int ITEM_HEIGHT = 88;

    private final int mGalleryItemBackground;
    private final Context mContext;

    private final Integer[] mImageIds = {
            R.drawable.gallery_photo_1,
            R.drawable.gallery_photo_2,
            R.drawable.gallery_photo_3,
            R.drawable.gallery_photo_4,
            R.drawable.gallery_photo_5,
            R.drawable.gallery_photo_6,
            R.drawable.gallery_photo_7,
            R.drawable.gallery_photo_8
    };

    private final float mDensity;

    public ImageAdapter(Context c) {
        mContext = c;
        // See res/values/attrs.xml for the <declare-styleable> that defines
        // Gallery1.
        TypedArray a = obtainStyledAttributes(R.styleable.Gallery1);
        mGalleryItemBackground = a.getResourceId(
                R.styleable.Gallery1_android_galleryItemBackground, 1);
        a.recycle();

        mDensity = c.getResources().getDisplayMetrics().density;
    }

    public int getCount() {
        return mImageIds.length;
    }

    public Object getItem(int position) {
        return position;
    }

    public long getItemId(int position) {
        return position;
    }

    public View getView(int position, View convertView, ViewGroup parent) {
        ImageView imageView;
        if (convertView == null) {
            convertView = new ImageView(mContext);

            imageView = (ImageView) convertView;
            imageView.setScaleType(ImageView.ScaleType.FIT_XY);
            imageView.setLayoutParams(new Gallery.LayoutParams(
                    (int) (ITEM_WIDTH * mDensity + 0.5f),
                    (int) (ITEM_HEIGHT * mDensity + 0.5f)));

        } else {
            imageView = (ImageView) convertView;
        }

        imageView.setImageResource(mImageIds[position]);

        return imageView;
    }
}

public boolean onTouch(View v, MotionEvent event) {

    if (event.getAction() == MotionEvent.ACTION_MOVE
            && event.getPointerCount() > 1) {
        midPoint(mid, event);

        if(mid.y > start.y){

            Log.i(TAG, "Going down (Math.abs(mid.y - start.y)= "+(Math.abs(mid.y - start.y))+" and zoom="+zoom); // going down so increase
            if ((Math.abs(mid.y - start.y) > 10) && (zoom<2.5f)){

                zoom=zoom+0.1f;
                midPoint(start, event);
                zoomList(true);


            }
            return true;
        }else if(mid.y < start.y){

            Log.i(TAG, "Going up (Math.abs(mid.y - start.y)= "+(Math.abs(mid.y - start.y))+" and zoom="+zoom); //smaller
            if ((Math.abs(mid.y - start.y) > 10) &&(zoom>0.1)){

                midPoint(start, event);
                zoom=zoom-0.1f;
                zoomList(false);

            }
            return true;
        }

    }

    else if (event.getAction() == MotionEvent.ACTION_POINTER_DOWN) {
        Log.e(TAG, "Pointer went down: " + event.getPointerCount());
        return true;
    }
    else if (event.getAction() == MotionEvent.ACTION_UP) {
        Log.i(TAG, "Pointer going up");
        return true;
    }
    else if (event.getAction() == MotionEvent.ACTION_DOWN) {
        Log.i(TAG, "Pointer going down");
        start.set(event.getX(), event.getY());
        return true;
    }

     return false;
       // indicate event was handled or not
   }

private void midPoint(PointF point, MotionEvent event) {
    float x = event.getX(0) + event.getX(1);
    float y = event.getY(0) + event.getY(1);
    point.set(x / 2, y / 2);
 }

I realise I will probably have to extend the Gallery or even another View group or create my own class but I don't know where to start: which method use the one responsible for scaling...

EDIT4: I don't know if he question is clear enough. Here is an example of states:

State one: initial state, we have 3 images in view

State 2: we detect vertical touches going up with 2 fingers = we have to zoom out

state 3: we start zooming = animation on the gallery or on the children???

state 4: gallery detects that it's 3 children are smaller

state 5: gallery adds 1 /more children according to the new available space

LAST UPDATE: Thanks to all that have posted but I have finally reached a conclusion and that is to not use Gallery at all: 1. It's deprecated 2. It's not customizable enough for my case

If you want to animate several images at once you may want to consider using OpenGl, I am using libgdx library: https://github.com/libgdx/libgdx

like image 460
vallllll Avatar asked Jul 13 '12 10:07

vallllll


People also ask

Is there a way to zoom out a picture on android?

Tap anywhere on the screen, except the keyboard or navigation bar. Drag 2 fingers to move around the screen. Pinch with 2 fingers to adjust zoom. To stop magnification, use your magnification shortcut again.

How do you zoom in and zoom out on Android?

Pinch 2 or more fingers together or apart to adjust zoom. To zoom temporarily, quickly tap the screen 3 times and hold down your finger on the third tap. Drag your finger to move around the screen. Lift your finger to zoom out.

How do you zoom in on an Android camera?

Open the Camera app, and pinch on the viewfinder to zoom. A zoom bar will appear to let you swiftly zoom in and out with your finger and change the zoom level with a simple swipe. There are also buttons below the viewfinder that appear so you can quickly zoom in to specific depths.


1 Answers

The following ScalingGallery implementation might be of help.
This gallery subclass overrides the getChildStaticTransformation(View child, Transformation t) method in which the scaling is performed. You can further customize the scaling parameters to fit your own needs.

Please note the ScalingGalleryItemLayout.java class. This is necessary because after you have performed the scaling operationg on the child views, their hit boxes are no longer valid so they must be updated from with the getChildStaticTransformation(View child, Transformation t) method.

This is done by wrapping each gallery item in a ScalingGalleryItemLayout which extends a LinearLayout. Again, you can customize this to fit your own needs if a LinearLayout does not meet your needs for layout out your gallery items.

File : /src/com/example/ScalingGallery.java

/**
 * A Customized Gallery component which alters the size and position of its items based on their position in the Gallery.
 */
public class ScalingGallery extends Gallery {

    public static final int ITEM_SPACING = -20;

    private static final float SIZE_SCALE_MULTIPLIER = 0.25f;
    private static final float ALPHA_SCALE_MULTIPLIER = 0.5f;
    private static final float X_OFFSET = 20.0f;

    /**
     * Implemented by child view to adjust the boundaries after it has been matrix transformed. 
     */
    public interface SetHitRectInterface {
        public void setHitRect(RectF newRect); 
    }

    /**
     * @param context
     *            Context that this Gallery will be used in.
     * @param attrs
     *            Attributes for this Gallery (via either xml or in-code)
     */
    public ScalingGallery(Context context, AttributeSet attrs) {
        super(context, attrs);
        setStaticTransformationsEnabled(true);
        setChildrenDrawingOrderEnabled(true);
    }

    /**
     * {@inheritDoc}
     * 
     * @see #setStaticTransformationsEnabled(boolean)
     *
     * This is where the scaling happens.
     */
    protected boolean getChildStaticTransformation(View child, Transformation t) {

        child.invalidate();

        t.clear();
        t.setTransformationType(Transformation.TYPE_BOTH);

        // Position of the child in the Gallery (... +2  +1  0  -1  -2 ... 0 being the middle)
        final int childPosition = getSelectedItemPosition() - getPositionForView(child);
        final int childPositionAbs = (int) Math.abs(childPosition);

        final float left = child.getLeft();
        final float top = child.getTop();
        final float right = child.getRight();
        final float bottom = child.getBottom();

        Matrix matrix = t.getMatrix();
        RectF modifiedHitBox = new RectF();

        // Change alpha, scale and translate non-middle child views.
        if (childPosition != 0) {

            final int height = child.getMeasuredHeight();
            final int width = child.getMeasuredWidth();

            // Scale the size.
            float scaledSize = 1.0f - (childPositionAbs * SIZE_SCALE_MULTIPLIER);
            if (scaledSize < 0) {
                scaledSize = 0;
            }
            matrix.setScale(scaledSize, scaledSize);

            float moveX = 0;
            float moveY = 0;

            // Moving from right to left -- linear move since the scaling is done with respect to top-left corner of the view.
            if (childPosition < 0) {
                moveX = ((childPositionAbs - 1) * SIZE_SCALE_MULTIPLIER * width) + X_OFFSET;
                moveX *= -1;

            } else { // Moving from left to right -- sum of the previous positions' x displacements.

                // X(n) = X(0) + X(1) + X(2) + ... + X(n-1)
                for (int i = childPositionAbs; i > 0; i--) {
                    moveX += (i * SIZE_SCALE_MULTIPLIER * width);
                }
                moveX += X_OFFSET;
            }

            // Moving down y-axis is linear.
            moveY = ((childPositionAbs * SIZE_SCALE_MULTIPLIER * height) / 2);

            matrix.postTranslate(moveX, moveY);

            // Scale alpha value.
            final float alpha = (1.0f / childPositionAbs) * ALPHA_SCALE_MULTIPLIER;
            t.setAlpha(alpha);

            // Calculate new hit box.  Since we moved the child, the hitbox is no longer lined up with the new child position.
            final float newLeft = left + moveX;
            final float newTop = top + moveY;
            final float newRight = newLeft + (width * scaledSize);
            final float newBottom = newTop + (height * scaledSize);
            modifiedHitBox = new RectF(newLeft, newTop, newRight, newBottom);
        } else {
            modifiedHitBox = new RectF(left, top, right, bottom);
        }

        // update child hit box so you can tap within the child's boundary
        ((SetHitRectInterface) child).setHitRect(modifiedHitBox);

        return true;
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {

        // Helps to smooth out jittering during scrolling.
        // read more - http://www.unwesen.de/2011/04/17/android-jittery-scrolling-gallery/
        final int viewsOnScreen = getLastVisiblePosition() - getFirstVisiblePosition();
        if (viewsOnScreen <= 0) {
            super.onLayout(changed, l, t, r, b);
        }
    }

    private int mLastDrawnPosition;

    @Override
    protected int getChildDrawingOrder(int childCount, int i) {

        //Reset the last position variable every time we are starting a new drawing loop
        if (i == 0) {
            mLastDrawnPosition = 0;
        }

        final int centerPosition = getSelectedItemPosition() - getFirstVisiblePosition();

        if (i == childCount - 1) {
            return centerPosition;
        } else if (i >= centerPosition) {
            mLastDrawnPosition++;
            return childCount - mLastDrawnPosition;
        } else {
            return i;
        }
    }
}

File : /src/com/example/ScalingGalleryItemLayout.java

public class ScalingGalleryItemLayout extends LinearLayout implements SetHitRectInterface {

    public ScalingGalleryItemLayout(Context context) {
        super(context);
    }

    public ScalingGalleryItemLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public ScalingGalleryItemLayout(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    private Rect mTransformedRect;

    @Override
    public void setHitRect(RectF newRect) {

        if (newRect == null) {
            return;
        }

        if (mTransformedRect == null) {
            mTransformedRect = new Rect();
        }

        newRect.round(mTransformedRect);
    }

    @Override
    public void getHitRect(Rect outRect) {

        if (mTransformedRect == null) {
            super.getHitRect(outRect);
        } else {
            outRect.set(mTransformedRect);
        }
    }
}

File : /res/layout/ScaledGalleryItemLayout.xml

<?xml version="1.0" encoding="utf-8"?>
<com.example.ScalingGalleryItemLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/gallery_item_layout"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:gravity="center"
    android:orientation="vertical"
    android:padding="5dp" >

    <ImageView
        android:id="@+id/gallery_item_image"
        android:layout_width="360px"
        android:layout_height="210px"
        android:layout_gravity="center"
        android:antialias="true"
        android:background="@drawable/gallery_item_button_selector"
        android:cropToPadding="true"
        android:padding="35dp"
        android:scaleType="centerInside" />

    <TextView
        android:id="@+id/gallery_item_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:textColor="@drawable/white"
        android:textSize="30sp" />

</com.example.ScalingGalleryItemLayout>
like image 143
Akos Cz Avatar answered Sep 29 '22 18:09

Akos Cz