一个难倒 3年 android开发经验 " 工程师 " 的 "bug"

  一个关于 imageView 设置 scaleType 的问题。

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

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

  先上事例图:

  理想效果 和 问题效果(左->右):

  公用的 xml:

 1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 2     xmlns:tools="http://schemas.android.com/tools"
 3     android:layout_width="match_parent"
 4     android:layout_height="match_parent"
 5     android:paddingBottom="@dimen/activity_vertical_margin"
 6     android:paddingLeft="@dimen/activity_horizontal_margin"
 7     android:paddingRight="@dimen/activity_horizontal_margin"
 8     android:paddingTop="@dimen/activity_vertical_margin"
 9     tools:context=".MainActivity" >
10 
11     <LinearLayout
12         android:id="@+id/images_container"
13         android:paddingLeft="10dp"
14         android:orientation="horizontal"
15         android:layout_width="wrap_content"
16         android:layout_height="wrap_content">
17         
18 
19 
20     </LinearLayout>
21 
22 
23 </RelativeLayout>

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

  imageView 的 xml:

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

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

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

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

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

   test.xml 换为:

 1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 2     xmlns:tools="http://schemas.android.com/tools"
 3     android:layout_width="match_parent"
 4     android:layout_height="match_parent"
 5     android:paddingBottom="@dimen/activity_vertical_margin"
 6     android:paddingLeft="@dimen/activity_horizontal_margin"
 7     android:paddingRight="@dimen/activity_horizontal_margin"
 8     android:paddingTop="@dimen/activity_vertical_margin"
 9     tools:context=".MainActivity" >
10 
11     <LinearLayout
12         android:id="@+id/images_container"
13         android:paddingLeft="10dp"
14         android:orientation="horizontal"
15         android:layout_width="wrap_content"
16         android:layout_height="wrap_content">
17         <ImageView
18             android:id="@+id/image"
19             android:scaleType="centerCrop"
20             android:layout_width="30dp"
21             android:layout_height="30dp" />
22 
23 
24     </LinearLayout>
25 
26 
27 </RelativeLayout>

java 换为

1 @Override
2     protected void onCreate(Bundle savedInstanceState) {
3         super.onCreate(savedInstanceState);
4         setContentView(R.layout.test);
5         final ImageView image = (ImageView)findViewById(R.id.image);
6         image.setImageResource(R.drawable.beni);
7     }

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

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

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

 1 /**
 2      * <p>Adds a child view. If no layout parameters are already set on the child, the
 3      * default parameters for this ViewGroup are set on the child.</p>
 4      * 
 5      * <p><strong>Note:</strong> do not invoke this method from
 6      * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
 7      * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
 8      *
 9      * @param child the child view to add
10      *
11      * @see #generateDefaultLayoutParams()
12      */
13     public void addView(View child) {
14         addView(child, -1);
15     }
16 
17 public void addView(View child, int index) {
18         if (child == null) {
19             throw new IllegalArgumentException("Cannot add a null child view to a ViewGroup");
20         }
21         LayoutParams params = child.getLayoutParams();
22         if (params == null) {
23             params = generateDefaultLayoutParams();
24             if (params == null) {
25                 throw new IllegalArgumentException("generateDefaultLayoutParams() cannot return null");
26             }
27         }
28         addView(child, index, params);
29     }
30 
31 protected LayoutParams generateDefaultLayoutParams() {
32         return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
33     }

因为没有自己传入 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 怎么办?自己加个宽高限制即可。
 1 @Override
 2     protected void onCreate(Bundle savedInstanceState) {
 3         super.onCreate(savedInstanceState);
 4         setContentView(R.layout.test);
 5         final ImageView image = (ImageView) LayoutInflater.from(this).inflate(R.layout.send_post_image, null, false);
 6         LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(50,50); /** 这里 */
 7         LinearLayout images_container = (LinearLayout) findViewById(R.id.images_container);
 8         image.setLayoutParams(lp); /** 添加 */
 9         image.setImageResource(R.drawable.beni);
10         Log.d("zzzzz", "" + image.getLayoutParams());
11         images_container.addView(image);
12     }

行了,快1点了。。。。

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

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏分享达人秀

Activity状态和生命周期方法

前面两期我们学习了Activity的创建和注册、以及启动和关闭,也学会了重写onCraete方法,这些知识在实际开发中远远不够,还需要学习了解更多。 ...

1966
来自专栏三好码农的三亩自留地

实现Activity滑动退出

很多应用在二级详情页面加入了滑动退出activity的效果,很方便,心血来潮,想着自己也来实现这个效果,就当做练手吧。

762
来自专栏jianhuicode

Fragment 学习笔记(1)

网上关于Fragment相关的博客资料很多,写关于这个知识笔记是加深记忆,大神略过; 0x01 了解Fragment 当然看官方文档(http://www.an...

1735
来自专栏Android中高级开发

Android开发之漫漫长途 Ⅲ——Activity的显示之Window和View(2)

该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列。该系列引用了《Android开发艺术探索...

893
来自专栏飞雪无情的博客

Android Activity的生命周期

通过上一节“Android系列之四:Android项目的目录结构”我们已经知道了什么是Activity,那么为什么我们创建一个Activity的导出类的时候为什...

583
来自专栏小巫技术博客

A010-menu资源

本节课讲Android中的菜单(menu)资源,这个也是我们在开发中可能经常用到的资源,它可以分为以下几种类型:

782
来自专栏CNN

Material Design Library 使用汇总

转载请注明出处:【huachao1001的专栏:http://blog.csdn.net/huachao1001】

742
来自专栏木头编程 - moTzxx

跑马灯 TextView效果设计

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u011415782/article/de...

482
来自专栏吴小龙同學

Android之LayoutParams

1385
来自专栏Jack的Android之旅

高仿网易严选底部弹出菜单

在网易严选的看东西的时候在商品详情页里看到他的底部弹出菜单,本能反应是想用DottomSheetDialog或者PopupWindow来实现,可是发现实现不了他...

772

扫码关注云+社区