在缩放时更改ImageView的大小

时间:2014-11-28 08:44:42

标签: android imageview pinchzoom image-zoom

我正在使用chrisbanes PhotoView来实现捏缩放..图像缩放捏和双击但我无法看到我的图像在变焦时拉伸到全屏...缩放它看起来图像放大到框内和部分图像的缩放在缩放时消失...我如何实现图像缩放,以便在缩放时图像的高度增加?我正在使用NetworkImageView(Volley库)。

NetworkImageView imageView;
 PhotoViewAttacher mAttacher;

                imageView = (NetworkImageView) mImgPagerView.findViewById(R.id.imageitem);

                mAttacher = new PhotoViewAttacher(imageView);

NetworkImageView.java(Volley库)

     import android.content.Context;
        import android.graphics.Bitmap;
        import android.text.TextUtils;
        import android.util.AttributeSet;
        import android.widget.ImageView;
        import com.android.volley.toolbox.ImageLoader.ImageContainer;

public class NetwrokImageView extends ImageView {
    /** The URL of the network image to load */
    private String mUrl;
    /**
     * Resource ID of the image to be used as a placeholder until the network image is loaded.
     */
    private int mDefaultImageId;
    /**
     * Resource ID of the image to be used if the network response fails.
     */
    private int mErrorImageId;
    /** Local copy of the ImageLoader. */
    private ImageLoader mImageLoader;
    public NetworkImageView(Context context) {
        this(context, null);
    }
    public NetworkImageView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }
    public NetworkImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }
    /**
     * Sets URL of the image that should be loaded into this view. Note that calling this will
     * immediately either set the cached image (if available) or the default image specified by
     * {@link NetworkImageView#setDefaultImageResId(int)} on the view.
     *
     * NOTE: If applicable, {@link NetworkImageView#setDefaultImageResId(int)} and
     * {@link NetworkImageView#setErrorImageResId(int)} should be called prior to calling
     * this function.
     *
     * @param url The URL that should be loaded into this ImageView.
     * @param imageLoader ImageLoader that will be used to make the request.
     */
    public void setImageUrl(String url, ImageLoader imageLoader) {
        mUrl = url;
        mImageLoader = imageLoader;
// The URL has potentially changed. See if we need to load it.
        loadImageIfNecessary();
    }
    /**
     * Sets the default image resource ID to be used for this view until the attempt to load it
     * completes.
     */
    public void setDefaultImageResId(int defaultImage) {
        mDefaultImageId = defaultImage;
    }
    /**
     * Sets the error image resource ID to be used for this view in the event that the image
     * requested fails to load.
     */
    public void setErrorImageResId(int errorImage) {
        mErrorImageId = errorImage;
    }
    /**
     * Loads the image for the view if it isn't already loaded.
     */
    private void loadImageIfNecessary() {
        int width = getWidth();
        int height = getHeight();
// if the view's bounds aren't known yet, hold off on loading the image.
        if (width == 0 && height == 0) {
            return;
        }
// if the URL to be loaded in this view is empty, cancel any old requests and clear the
// currently loaded image.
        if (TextUtils.isEmpty(mUrl)) {
            ImageContainer oldContainer = (ImageContainer) getTag();
            if (oldContainer != null) {
                oldContainer.cancelRequest();
                setImageBitmap(null);
            }
            return;
        }
        ImageContainer oldContainer = (ImageContainer) getTag();
// if there was an old request in this view, check if it needs to be canceled.
        if (oldContainer != null && oldContainer.getRequestUrl() != null) {
            if (oldContainer.getRequestUrl().equals(mUrl)) {
// if the request is from the same URL, return.
                return;
            } else {
// if there is a pre-existing request, cancel it if it's fetching a different URL.
                oldContainer.cancelRequest();
                setImageBitmap(null);
            }
        }
// The pre-existing content of this view didn't match the current URL. Load the new image
// from the network.
        ImageContainer newContainer = mImageLoader.get(mUrl,
                ImageLoader.getImageListener(this, mDefaultImageId, mErrorImageId));
// update the tag to be the new bitmap container.
        setTag(newContainer);
// look at the contents of the new container. if there is a bitmap, load it.
        final Bitmap bitmap = newContainer.getBitmap();
        if (bitmap != null) {
            setImageBitmap(bitmap);
        }
    }
    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        loadImageIfNecessary();
    }
    @Override
    protected void onDetachedFromWindow() {
        ImageContainer oldContainer = (ImageContainer) getTag();
        if (oldContainer != null) {
// If the view was bound to an image request, cancel it and clear
// out the image from the view.
            oldContainer.cancelRequest();
            setImageBitmap(null);
// also clear out the tag so we can reload the image if necessary.
            setTag(null);
        }
        super.onDetachedFromWindow();
    }
    @Override
    protected void drawableStateChanged() {
        super.drawableStateChanged();
        invalidate();
    }
}

的build.gradle

compile 'com.github.chrisbanes.photoview:library:+'

XML

<com.xyz.NetworkImageView
            android:id="@+id/imageitem"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:scaleType="matrix"
            android:layout_gravity="center"
            android:adjustViewBounds="true"
            android:background="@drawable/image_loading" />

ImageView位于FrameLayout

    <FrameLayout
        android:id="@+id/image_holder"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:background="@color/black"
        >

缩放前的图像 enter image description here 缩放后的图像 enter image description here

8 个答案:

答案 0 :(得分:1)

如果你陷入困境,最好尝试不同的方法

您可以在下面找到由Jason Polites创建的类的链接,该类允许您处理自定义ImageView上的缩放缩放:https://github.com/jasonpolites/gesture-imageview

只需将此软件包包含到您的应用程序中,然后您就可以在XML文件中使用自定义GestureImaveView

<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:gesture-image="http://schemas.polites.com/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">

<com.polites.android.GestureImageView
    android:id="@+id/image"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:src="@drawable/image"
    gesture-image:min-scale="0.1"
    gesture-image:max-scale="10.0"
    gesture-image:strict="false"/>

此类处理缩放缩放,但也可以双击。

答案归功于Yoann:)

答案 1 :(得分:1)

我强烈建议您查看照片视图:

https://github.com/chrisbanes/PhotoView

它是由Chris Banes开发的,他是开发Android开发团队的实际开发人员之一,所以你不会在这里出错。这个库可以为您节省很多麻烦。

用法很简单:

ImageView mImageView;
PhotoViewAttacher mAttacher;

@Override
public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);

  // Any implementation of ImageView can be used!
  mImageView = (ImageView) findViewById(R.id.iv_photo);

  // Set the Drawable displayed
  Drawable bitmap = getResources().getDrawable(R.drawable.wallpaper);
  mImageView.setImageDrawable(bitmap);

  // Attach a PhotoViewAttacher, which takes care of all of the zooming functionality.
  mAttacher = new PhotoViewAttacher(mImageView);
}

答案 2 :(得分:1)

我在github上创建了一个功能齐全的项目。链接在答案的最后。

问题元素:

1。获取触摸事件并使用它的变量来设置图像缩放级别和窗口。 (左,上,右,下)。

示例代码:一次只显示部分图片。因此设置android:scaleType="fitCenter"将实现缩放。

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/imageFrameLayout"
    android:background="@android:color/black">

    <ImageView android:id="@+id/imageView"
        android:layout_width="0px"
        android:layout_height="0px"
        android:layout_gravity="center"
        android:scaleType="fitCenter"
        android:background="@android:color/transparent" />

</FrameLayout>

触摸侦听器(您可以修改此选项以添加点击事件)

OnTouchListener MyOnTouchListener = new OnTouchListener() {
    @Override
    public boolean onTouch(View view, MotionEvent event) {
        float distx, disty;
        switch(event.getAction() & MotionEvent.ACTION_MASK){   
            case MotionEvent.ACTION_DOWN:
                //A pressed gesture has started, the motion contains the initial starting location.
                touchState = TOUCH;
                currentX = (int) event.getRawX();
                currentY = (int) event.getRawY();
            break;

            case MotionEvent.ACTION_POINTER_DOWN:
                //A non-primary pointer has gone down.
                touchState = PINCH;
                //Get the distance when the second pointer touch
                distx = event.getX(0) - event.getX(1);
                disty = event.getY(0) - event.getY(1);

                dist0 = (float) Math.sqrt(distx * distx + disty * disty);
                distLast = dist0;
            break;

            case MotionEvent.ACTION_MOVE:
                //A change has happened during a press gesture (between ACTION_DOWN and ACTION_UP).
                if(touchState == PINCH){
                    // pinch started calculate scale step.
                    //Get the current distance
                    distx = event.getX(0) - event.getX(1);
                    disty = event.getY(0) - event.getY(1);
                    distCurrent = (float) Math.sqrt(distx * distx + disty * disty);
                    if (Math.abs(distCurrent-distLast) >= 35) // check sensitivity
                    {
                        stepScale = distCurrent/dist0;
                        distLast = distCurrent;
                        drawMatrix(); // draw new image
                    }
                }
                else
                {
                    // move started.
                    if (currentX==-1 && currentY==-1) 
                    {
                        // first move after touch down
                        currentX = (int) event.getRawX();
                        currentY = (int) event.getRawY();
                    }
                    else
                    {
                        // calculate move window variable.
                        int x2 = (int) event.getRawX();
                        int y2 = (int) event.getRawY();
                        int dx = (currentX - x2);
                        int dy = (currentY - y2);
                        left += dx;
                        top += dy;
                        currentX = x2;
                        currentY = y2;
                        drawMatrix(); // draw new image window
                    }
                }
            break;

            case MotionEvent.ACTION_UP:
                //A pressed gesture has finished.

                touchState = IDLE;
            break;

            case MotionEvent.ACTION_POINTER_UP:
                //A non-primary pointer has gone up.
                if (touchState == PINCH)
                {
                    // pinch ended. reset variable.
                }
                touchState = TOUCH;
            break;
        }
        return true;
    }
};

2。由于需要缩放。我假设我们正在使用高质量的图像。

因此,在缩小时加载全尺寸质量图像不会带来好处,因为用户不会识别小细节。但它会增加内存使用量,并且可能会因非常大的图像而崩溃。

  

解决方案技巧:在缩小加载较大窗口时降低质量。   放大加载较小窗口,质量更高。

建议的解决方案检查所需的当前缩放级别和图像窗口,并根据该窗口仅使用 BitmapRegionDecoder BitmapFactory 获得具有特定质量的图像的一部分。

示例代码:

初始化图像解码器,稍后将用于询问图像的一部分:

    InputStream is = null;
    bitmapRegionDecoder = null;

    try {
        is = getAssets().open(res_id); // get image stream from assets. only the stream, no mem usage
        bitmapRegionDecoder = BitmapRegionDecoder.newInstance(is, false);

    } catch (IOException e) {
        e.printStackTrace();
    }

    bounds = new BitmapFactory.Options();
    bounds.inJustDecodeBounds = true; // only specs needed. no image yet!
    BitmapFactory.decodeStream(is, null, bounds); // get image specs.

    try {
        is.close(); // close stream no longer needed.
    } catch (IOException e) {
        e.printStackTrace();
    }

要求图像质量和窗口:

    Rect pRect = new Rect(left, top, left + newWidth, top + newHeight);
    BitmapFactory.Options bounds = new BitmapFactory.Options();
    int inSampleSize = 1;
    if (tempScale <= 2.75) // you can map scale with quality better than this.
        inSampleSize = 2;

    bounds.inSampleSize = inSampleSize; // set image quality. takes binary steps only. 1, 2, 4, 8 . .
    bm = bitmapRegionDecoder.decodeRegion(pRect, bounds);
    imageView.setImageBitmap(bm);

project on github

答案 3 :(得分:1)

我在照片查看图像缩放库中遇到了这个问题。我已将layout_height从“ wrap_content”更改为“ match_parent”。它对我来说很好。

https://github.com/chrisbanes/PhotoView

<com.xyz.NetworkImageView
        android:id="@+id/imageitem"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scaleType="matrix"
        android:layout_gravity="center"
        android:adjustViewBounds="true"
        android:background="@drawable/image_loading" />

答案 4 :(得分:0)

如果您希望更改ImageView的大小,则需要更改其layoutParams,因为我已经演示了here。你也可以改变它的规模,从Honeycomb。

但是,如果你想在图像中移动一个矩形,它也可以很好地缩放(就像其他允许裁剪的应用程序一样),你可以使用像"cropper&#34;这样的库。或者,如果您不需要这些功能,可以使用TouchImageView

等库

答案 5 :(得分:0)

这是因为ImageView的视图高度为“wrap_content”。将其更改为“match_parent”并将图像的scaleType设置为“centerInside”以解决您的问题。

答案 6 :(得分:0)

问题在于,当使用NetworkImageView的行为与ImageView不同时,我通过为纵向和横向创建xml设计来解决它

<强>纵向

<强>布局/ item_image.xml

height =“match_parent”和width =“wrap_content”,重要 scaleType =“fitCenter”

 <com.android.volley.toolbox.NetworkImageView
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:scaleType="fitCenter"
        android:background="@android:color/transparent"
        android:id="@+id/imageitem"/>

<强> LAND

<强>布局/土地/ item_image.xml

现在在土地布局中,height =“wrap_content”和width =“match_parent”,总是 scaleType =“fitCenter”

 <com.android.volley.toolbox.NetworkImageView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:scaleType="fitCenter"
        android:background="@android:color/transparent"
        android:id="@+id/imageitem"/>

在将资源分配给NetworkImageView控件后实例化PhotoViewAttacher对象也很重要

    NetworkImageView imageView;
    PhotoViewAttacher mAttacher;

        imageView = (NetworkImageView) 
        mImgPagerView.findViewById(R.id.imageitem);
        //firts set the image resources, i'm using Android Volley Request
        ImageLoader imageLoader = MySocialMediaSingleton.getInstance(context).getImageLoader();
        imageView.setImageUrl(url, imageLoader);
        //next create instance of PhotoViewAttecher
        mAttacher = new PhotoViewAttacher(imageView);
        mAttacher.update();

答案 7 :(得分:0)

我使用imageviewtouch并遇到相同的问题。为了解决这个问题,您可以将imageview包装在布局内,而无需任何其他子项。示例:

<LinearLayout
android:id="@+id/layout"
    android:layout_width="match_parent"
    android:layout_height="0dp"
    android:layout_marginBottom="200dp"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/toplayout">

    <com.android.volley.toolbox.NetworkImageView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:scaleType="fitCenter"
    android:background="@android:color/transparent"
    android:id="@+id/imageitem"/>
</LinearLayout>