最近遇到一个问题:

我们在显示一张图片时,需要的效果像:

iOS 图片偏移_图片


使用ImageView需要固定宽高比,但给定图片的宽高比是不一样的,怎么使内容在view 中,且图片不变形呢?这时候,单纯的使用ImageView的ScaleType属性不是让图片变形就是我们要显示的内容点被切除出去了。

ios方面:图片根据内容中心点移动位置:
https://github.com/totemtec/UIImageViewAligned

android方面:我试过两种方法

一:在设置ImageView的图片前,先根据获取的BitMap重新切出一个新的bitmap
使用的方法是createBitmap(bitmap, x, y,bitmap.getWidth() - x, (int) (bitmap.getWidth() * 0.65526316d));x,y是计算出来要从该位置开始切出一个一个长宽比例为0.65526316d 的bitmap后放入ImageView 中。
这个方法目前只对长比宽大的情况下有效,当宽比长大时会出错。而且对内存也有影响。

代码如下:

//x1,y1是内容点在图片上的比例点
        double x1 = 0.6;
        double y1 = 0.7;
        //拿到获得的bitmap的宽高
        int imgw = bitmap.getWidth();
        int imgh = bitmap.getHeight();
        //计算内容点的坐标
        int w = (int) (imgw * x1);
        int h = (int) (imgh * y1);
        //计算我们切出bitmap的起始点,如果内容点原本就在imageview
        //的前半部分,我们就不需要在切出来了
        int x = (show_img.getWidth() / 2 >= w) ? 0 : (w - show_img.getWidth() / 2);
        int y = (show_img.getHeight() / 2 >= h) ? 0 : (h - show_img.getHeight() / 2);
        //新建一个bitmap
        Bitmap bi = Bitmap.createBitmap(bitmap, x, y, img1.getWidth() - x, (int) (img1.getWidth() * 0.65526316d));
        show_img.setImageBitmap(bi);

二:使用ImageView 的setImageMatrix()方法,将图片按计算出来的数据平移,将内容移动到ImageView区域,这里必须要将ImageView的属性android:scaleType=”matrix”设置为matrix。
这里使用imageLoader三方库来加载图片,记得使用前初始化它
imageLoader的使用情趣看其他人的、、

//初始化imageLoader
     imageLoader.init(ImageLoaderConfiguration.createDefault(ImgListviewActivity.this));

下面是关键代码:

//原图,我们常用的
            imageLoader.displayImage(list.get(position), holder.img,getOptions());
            //移动图,借用Listener能获取到它的bitmap
            imageLoader.displayImage(list.get(position), holder.show_img, getOptions(), new SimpleImageLoadingListener() {
                @Override
                public void onLoadingComplete(String imageUri, View view, Bitmap bitmap) {
                    super.onLoadingComplete(imageUri, view, bitmap);

                    ImageView imgv = (ImageView) view;
                    Matrix matrix = new Matrix();
                    float bitmapWidth = bitmap.getWidth();
                    float bitmapHeight = bitmap.getHeight();
                    //内容中心点所在图片的比例坐标
                    float Face_center_x = 0.5f;
                    float Face_center_y = 0.5f;
                    //缩放比例、使图片填充满view
                    float Scale = (imgv.getHeight() / bitmapHeight >= imgv.getWidth() / bitmapWidth) ? imgv.getHeight() / bitmapHeight : imgv.getWidth() / bitmapWidth;
                    matrix.postScale(Scale, Scale);
                    //缩放后的图片宽高
                    float scaleBitmapWidth = Scale * bitmapWidth;
                    float scaleBitmapHeight = Scale * bitmapHeight;

                    if (scaleBitmapWidth > scaleBitmapHeight) {  //宽度图
                        //移动的距离计算,下方有解释
                        float translate = (imgv.getWidth() / 2 >= Face_center_x * scaleBitmapWidth) ? 0 : ((Face_center_x * scaleBitmapWidth) - imgv.getWidth() / 2);
                        if (scaleBitmapWidth - translate <= imgv.getWidth()) {
                            translate = scaleBitmapWidth - imgv.getWidth();
                        }
                        matrix.postTranslate(-translate, 0);
                    } else {  //高度图
                        float translate = (imgv.getHeight() / 2 >= Face_center_y * scaleBitmapHeight) ? 0 : ((Face_center_y * scaleBitmapHeight) - imgv.getHeight() / 2);
                        if (scaleBitmapHeight - translate <= imgv.getHeight()) {
                            translate = scaleBitmapHeight - imgv.getHeight();
                        }
                        matrix.postTranslate(0, -translate);
                    }
                    imgv.setImageMatrix(matrix);
                    imgv.setImageBitmap(bitmap);

                }
            });

计算移动距离的公式

float translate = (imgv.getWidth() / 2 >= Face_center_x * scaleBitmapWidth) ? 0 
                        : ((Face_center_x * scaleBitmapWidth) - imgv.getWidth() / 2);
     if (scaleBitmapWidth - translate <= imgv.getWidth()) {
                            translate = scaleBitmapWidth - imgv.getWidth();
                        }

这是宽度图的计算公式

imgv.getWidth() / 2 >= Face_center_x * scaleBitmapWidth 是判断内容中心点在左边多远,需不需要平移。如图

iOS 图片偏移_图片_02


下面是判断会不会移动过头,造成右边出现空白的情况

if (scaleBitmapWidth - translate <= imgv.getWidth()) { 
 translate = scaleBitmapWidth - imgv.getWidth(); 
 }

iOS 图片偏移_imageview_03

getOptions()是图片加载的一些情况

public DisplayImageOptions getOptions() {
        DisplayImageOptions options = new DisplayImageOptions.Builder()
                .showStubImage(R.drawable.ic_launcher)          // 设置图片下载期间显示的图片
                .showImageForEmptyUri(R.drawable.ic_launcher)  // 设置图片Uri为空或是错误的时候显示的图片
                .showImageOnFail(R.drawable.ic_launcher)       // 设置图片加载过程中发生错误显示的图片
                .cacheInMemory(true)                        // 设置下载的图片是否缓存在内存中
                .cacheOnDisc(true)                           // 设置下载的图片是否缓存在SD卡中
                .build();                                   // 创建配置过得DisplayImageOption对象
        return options;
    }

设置View的宽高方法:

private int width = 0;
    private int height = 0;
    private void scaleImage(ImageView view) {
        //获取屏幕的宽高
        WindowManager wm = (WindowManager) this.getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics outMetrics = new DisplayMetrics();
        wm.getDefaultDisplay().getMetrics(outMetrics);
        if (width == 0) {
            width = outMetrics.widthPixels;
        }
        if (height == 0) {
            height = (int) (width * 0.65526316d);
        }
        LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) view.getLayoutParams();
        if (params == null) {
            params = new LinearLayout.LayoutParams(width, height);
        } else {
            params.height = height;
            params.width = width;
        }
        view.setLayoutParams(params);
    }

这个方法每个图片加载都会走三遍,我也不清楚情况、、、

如果有其他方法或者你发现的缺陷,请告知我,谢谢。