Android相册缩放(放大/缩小)

7

你好,我正在使用画廊小部件展示从互联网下载的图像。

我想展示几张图片,并希望在用户上下滑动屏幕时有逐渐放大的效果。我知道如何实现触摸事件,唯一不知道的是如何使整个画廊视图逐渐变大。我不想只放大一张图片,而是希望整个画廊可以逐渐放大/缩小。

编辑3:我已经成功地将可见部分的画廊进行了缩放,但问题是我需要找到一种方法让画廊能够发现并更新其它子元素。

如果有3张图片可见,然后开始缩放,画廊确实会变小,图片也会变小,但是我希望在这种情况下能看到更多的图片,但我不知道如何达到这个效果。以下是完整的代码:

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);
 }

我意识到我可能需要扩展Gallery或其他View组或创建自己的类,但我不知道从哪里开始:哪个方法负责缩放... 编辑4:我不知道问题是否清晰。以下是状态示例: 状态1:初始状态,我们在视图中有3个图像 状态2:我们检测到使用2个手指向上滑动 = 我们必须缩小 状态3:我们开始缩放=在画廊或子元素上进行动画吗? 状态4:画廊检测到它的3个子元素变小 状态5:画廊根据新的可用空间添加1 /多个子元素 最后更新: 感谢所有发布帖子的人,但我最终得出结论,就是根本不使用Gallery: 1.已弃用 2.对于我的情况而言,它的可定制性不够 如果您想同时动画化多个图像,则可以考虑使用OpenGl,我正在使用libgdx库: https://github.com/libgdx/libgdx
4个回答

4
以下的ScalingGallery实现或许能帮到你。
这个画廊子类重写了getChildStaticTransformation(View child, Transformation t)方法,在其中执行缩放操作。你可以进一步自定义缩放参数以适应自己的需求。
请注意ScalingGalleryItemLayout.java类。这是必要的,因为在对子视图进行缩放操作后,它们的点击区域将不再有效,因此必须从getChildStaticTransformation(View child, Transformation t)方法中更新它们。这是通过将每个画廊项包装在扩展LinearLayout的ScalingGalleryItemLayout中完成的。同样,如果LinearLayout不能满足您布置画廊项的需求,您可以自定义它。
文件:/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;
        }
    }
}

文件路径:/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>

谢谢Akos的回答。我已经尝试过了,但是由于我在画廊上使用了动画效果,结果与之前相同:可见部分缩小,但没有新视图被绘制。如果我只将动画应用于一个视图,那么只有该视图会放大。如果我使用scaleX / scaleY,情况也是一样的... 我已经决定创建自己的Surfaceview并绘制位图。 - vallllll
请将您的完整代码放在这里……我需要它很紧急……提前感谢! - Denny Sharma
@Akos Cz,我尝试了你的解决方案,但它不起作用。出现了ArrayIndexOutOfBoundsException错误。 - kyogs

1

你说得没错,但是我正在使用animSet,所以必须将其应用于整个集合,但这并不能解决我的问题:动画会重新调整画廊的比例,但不是我想要的方式。当画廊变小时,我希望它能显示更多的图片,但在我的情况下,它仍然只显示一张图片,因此整个布局会缩小。 - vallllll
是的,我看过那段代码,它很棒,但是有很多示例处理图像缩放。问题在于我需要同时缩放多个图像,并且画廊应该根据缩放级别自动调整大小以显示一个或多个图像。 - vallllll

0

这是一个解决方案:在Android中使用gesture-image库集成相册组件 gesture-imageView

下面是完整的示例代码 SampleCode


请勿在多个问题之间复制粘贴答案。此外,仅提供链接的答案通常不受欢迎,因此您能否更详细地解释为什么链接的GitHub项目将解决手头的确切问题?最后,我们希望您将示例代码放在其他地方而不是MediaFire,因为这些链接很快就会失效。 - Brad Larson

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接