缩放时更改 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.由于需要缩放。我假设我们正在使用高质量的图像。
因此,在缩小时加载全尺寸质量图像不会受益,因为用户不会识别小细节。但它会增加内存使用量,并且对于非常大的图像可能会崩溃。
解决方案技巧:缩小时加载质量较低的较大窗口。 放大时加载质量更高的小窗口。
建议的解决方案检查当前所需的缩放级别和图像窗口,并在此基础上使用 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.
【讨论】:
【参考方案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 的大小的主要内容,如果未能解决你的问题,请参考以下文章