缩放时更改 ImageView 的大小

Posted

技术标签:

【中文标题】缩放时更改 ImageView 的大小【英文标题】:Change the size of ImageView on zooming 【发布时间】:2015-01-26 21:17:16 【问题描述】:

我正在使用 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_
            android:layout_
            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_
        android:layout_
        android:layout_centerVertical="true"
        android:background="@color/black"
        >

缩放前的图像 缩放后的图像

【问题讨论】:

我不确定我是否遇到了您的问题。也许this 有帮助? @DerGolem 除了这段代码,我什至尝试使用 ChrisBanes github.com/chrisbanes/PhotoView,但存在同样的问题..图像在捏合和双击时缩放,但图像视图的大小保持固定..缩放时不会增加..我想就像在whatsapp中imageview的大小在缩放时增加..也许我的布局文件中有一些问题,这就是我发布完整的xml布局文件的原因..请检查一下.. 我不使用 WhatsApp(我使用 Telegram),所以我无法计算这种“ImageView”缩放,而不是“图像缩放”。是你的意思吗? ImageView 必须根据其内容更改大小? 是的..imageview 必须根据内容更改大小..所以当我缩放图像时,图像视图应该增加大小..但是在这里我的 imageview 在放大和缩放时保持固定大小-出来,但图像确实放大了放大 我刚刚发现这个:***.com/a/5355281/2649012。如果我理解正确,它所做的就是使 ImageView 适合其内容。默认为假。 【参考方案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_
android:layout_>

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

这个类处理捏缩放,但也可以双击。

答案归Yoann :)

【讨论】:

我认为问题在于图像缩放时图像容器不会调整大小。请查看上面的完整 java 代码 我试过这个..我的 ImageView 正在扩展这个..android.googlesource.com/platform/frameworks/volley/+/… ..我使用github.com/chrisbanes/PhotoView 仍然看不到我的图像在缩放时拉伸到全屏..在缩放时看起来图像在框内放大,部分图像在缩放时消失【参考方案2】:

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

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

【讨论】:

在我的项目中还需要向单击添加功能。 ? 我的 ImageView 正在扩展这个..android.googlesource.com/platform/frameworks/volley/+/… ..我使用 chrisbanes PhotoView 仍然看不到我的图像在缩放时拉伸到全屏..在缩放时看起来图像在里面放大一个框和部分图像在缩放时消失【参考方案3】:

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

问题要素:

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

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

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

    <ImageView android:id="@+id/imageView"
        android:layout_
        android:layout_
        android:layout_gravity="center"
        android:scaleType="fitCenter"
        android:background="@android:color/transparent" />

</FrameLayout>

Touch Listener(你可以修改它来添加你的点击事件)

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.由于需要缩放。我假设我们正在使用高质量的图像。

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

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

建议的解决方案检查当前所需的缩放级别和图像窗口,并在此基础上使用 BitmapRegionDecoderBitmapFactory 获取具有特定质量的图像的一部分。

示例代码:

初始化稍后将用于请求图像的一部分的图像解码器:

    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.

【讨论】:

【参考方案4】:

我在照片视图图像缩放库中遇到过这个问题。我已将 layout_height 的“wrap_content”更改为“match_parent”。它对我来说工作正常。

https://github.com/chrisbanes/PhotoView

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

【讨论】:

【参考方案5】:

如果你想改变 ImageView 的大小,你需要改变它的 layoutParams,正如我在here 中演示的那样。你也可以像 Honeycomb 一样改变它的规模。

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

【讨论】:

我认为问题是图像缩放时图像容器不会调整大小 当我拖动图像时,它看起来像是在矩形容器中,当我将它拖到容器外时,部分图像消失了.. 请检查我上面的代码..我认为问题是 ImageContainer mImageContainer 在我缩放图像时不会调整大小.. 代码太长。您能否发布一个我可以导入并运行的示例(并使用尽可能短的代码)项目?也许还发布一个视频来说明问题所在? 请上传到一个文件上传网站,整个项目,但最小化,以便我可以专注于问题并轻松找到它。【参考方案6】:

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

【讨论】:

【参考方案7】:

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

肖像

布局/item_image.xml

和 ,重要 scaleType="fitCenter"

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

土地

layout/land/item_image.xml

现在在土地布局中, 和 ,总是 scaleType="fitCenter"

 <com.android.volley.toolbox.NetworkImageView
        android:layout_
        android:layout_
        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();

【讨论】:

【参考方案8】:

我使用 imageviewtouch 并且有同样的问题。要解决它,您可以将 imageview 包装在布局中而无需任何其他子级。示例:

<LinearLayout
android:id="@+id/layout"
    android:layout_
    android:layout_
    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_
    android:layout_
    android:scaleType="fitCenter"
    android:background="@android:color/transparent"
    android:id="@+id/imageitem"/>
</LinearLayout>

【讨论】:

以上是关于缩放时更改 ImageView 的大小的主要内容,如果未能解决你的问题,请参考以下文章

向下滚动时 ImageView 缩放

根据来自服务器的图像调整imageview大小,然后调整其他标签

imageView添加阴影和边框

Swift 3 - 缩放圆形 ImageView

Android ImageView 大小不随源图像缩放

android ImageView图片缩放至屏幕大小