一个关于 imageView 设置 scaleType 的问题

就在刚才 晚上9 点多的时候,我的一个外包伙伴发一个工程代码我,叫我去看下这样一个"bug",说折腾了很久,图片选择器在选择完图片后,就要显示图片到界面上,大家可以想象下 微信 发表图片,因为我们相机的图片肯定是 长宽都不一致的,为了统一格式,一般都是把要显示出来的 imageView 设置成 scaleType = centerCrop 或者 center。

  问题就是:他在设置了上面的属性后,宛然无效!imageView 设置成 scaleType = centerCrop 或者 center,对图片没效果。

  先上事例图:

  理想效果 和 问题效果(上->下):



公用的 xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <LinearLayout
        android:id="@+id/images_container"
        android:paddingLeft="10dp"
        android:orientation="horizontal"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">
        


    </LinearLayout>


</RelativeLayout>

我们来看看出问题的代码:

  imageView 的 xml:


<?xml version="1.0" encoding="utf-8"?>
<ImageView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/image_one"
    android:scaleType="centerCrop"
    android:layout_width="30dp"
    android:layout_height="30dp" />

他设置了动态 addView() 的方法 添加用户选中的 图片,java 代码,为了避免长篇大论,我已做简化,事例效果一样:

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.test);
        final ImageView image = (ImageView) LayoutInflater.from(this).inflate(R.layout.send_post_image, null, false);
        LinearLayout images_container = (LinearLayout) findViewById(R.id.images_container);
        image.setImageResource(R.drawable.beni);
        images_container.addView(image);
    }

这样的代码,貌似没什么问题,通过 LayoutInflater.from(this).inflate(...) 来事例化一个 View,而最为之关键的是,这个View 就是上面的 imageView的xml,里面明确设置了 width 和 height 是 30dp,显示方式是 centerCrop,最后通过 addView 添加到一个 linearLayout 中。但是,这份代码显示出来的效果是 右图,非 理想效果!!哈哈,感觉恍然大悟吧。

   你可能会有这样一个印象,我们绝大多项目或者是练习中的 imageVIew 使用都是直接 findViewById, 一样的 imageView 设置,却没问题, 没错,的确没问题,你可以把上面的代码替换为这个试试:


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <LinearLayout
        android:id="@+id/images_container"
        android:paddingLeft="10dp"
        android:orientation="horizontal"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">
        <ImageView
            android:id="@+id/image"
            android:scaleType="centerCrop"
            android:layout_width="30dp"
            android:layout_height="30dp" />
    </LinearLayout>
</RelativeLayout>

 java 换为

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.test);
        final ImageView image = (ImageView)findViewById(R.id.image);
        image.setImageResource(R.drawable.beni);
    }

这样显示出来的 效果 就是我们所 期望的。

   为什么通过 addView() 的方法却败了呢

   问题的原因是这样的:任何使用 addView(...) 的方法,无论你所实例化的 View 本身的 xml 的 width 和 height 设置了什么,都是没效果的,请看清楚,是 width height 失效,上面的 scaleType 是有效的, 问题 java 代码中调用 addView 的时候并没有传入 LayoutParam 布局参数,好了,我们来 粘下 源码,见证真相只有一个。


/**
     * <p>Adds a child view. If no layout parameters are already set on the child, the
     * default parameters for this ViewGroup are set on the child.</p>
     * 
     * <p><strong>Note:</strong> do not invoke this method from
     * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
     * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
     *
     * @param child the child view to add
     *
     * @see #generateDefaultLayoutParams()
     */
    public void addView(View child) {
        addView(child, -1);
    }

public void addView(View child, int index) {
        if (child == null) {
            throw new IllegalArgumentException("Cannot add a null child view to a ViewGroup");
        }
        LayoutParams params = child.getLayoutParams();
        if (params == null) {
            params = generateDefaultLayoutParams();
            if (params == null) {
                throw new IllegalArgumentException("generateDefaultLayoutParams() cannot return null");
            }
        }
        addView(child, index, params);
    }

protected LayoutParams generateDefaultLayoutParams() {
        return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
    }

因为没有自己传入 LayoutParam 而 get 的又是 null ,为什么 get 的会是null,请在上面的事例代码中加入这句 log ,Log.d("zzzzz",""+image.getLayoutParams()); ,就会看到输出 null 了,而最终调用源码的:

protected LayoutParams generateDefaultLayoutParams() {
return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
}
直接使用了 Wrap_parent,所以啊,导致了失效。那我就是要使用 addView 怎么办?自己加个宽高限制即可。

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.test);
        final ImageView image = (ImageView) LayoutInflater.from(this).inflate(R.layout.send_post_image, null, false);
        LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(50,50); /** 这里 */
        LinearLayout images_container = (LinearLayout) findViewById(R.id.images_container);
        image.setLayoutParams(lp); /** 添加 */
        image.setImageResource(R.drawable.beni);
        Log.d("zzzzz", "" + image.getLayoutParams());
        images_container.addView(image);
    }

总结下。 导致这样的事情发生,我觉得还是缺少自己动手踏实编码的问题,现在框架比较泛滥了,又想起了那句老话:我们不生产代码,我们都是 github 的搬运工 ...











评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值