【发布时间】:2012-10-18 01:10:50
【问题描述】:
我开发了这个自定义的ImageView 类来覆盖一些默认行为以满足我的需要。让我描述一下这个自定义 ImageView 的作用......
假设你在GridView 和drawable-mdpi 和drawable-hdpi 文件夹中有一堆图标要显示,它们的大小分别为48x48px 和72x72px。 drawable-xhdpi 文件夹中没有可用的图标。 GridView 属性使所有图标大小都为 48x48dp(对于 mpdi、hdpi 和 xhdpi 密度,这将分别转换为 48px、72px 和 96px)。
由于drawable-xhdpi 文件夹中没有图标,因此当此应用程序在如此密度的设备上运行时,图标将从drawable-hdpi 文件夹中拉出。 由于它们只有 72 像素,而 xhdpi 设备需要 96 像素的图像,因此图标将被拉伸以填充剩余的像素。
这是我的自定义 ImageView 尝试覆盖的行为。使用我的自定义组件,将发生的情况是图像根本不会被拉伸。例如,在上面使用我的类的示例中,GridView 中的每个 ImageView 仍将是 96x96px(因为定义了 48x48dp 大小),但使用的图像来自 drawable-hdpi 文件夹,大小为 72x72px。 将会发生的情况是,drawable-hdpi 文件夹中的这些图像将被放置在尺寸为 96x96 像素的 ImageView 的中心,而不会拉伸图像以适应整个视图大小。
如果以上内容令人困惑,让我们尝试几张图片。下面的示例不使用GridView,我试图简化我的自定义类背后的想法。这些是我用于此示例的源图片:
这是 HDPI 设备上的结果:
这是 XHDPI 设备上的结果:
上面截图中的布局代码是这样的:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="10dp"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Standard ImageView:"
android:textAppearance="?android:attr/textAppearanceLarge"/>
<ImageView
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_margin="10dp"
android:scaleType="center"
android:background="#FFEEEE"
android:src="@drawable/ic_female"/>
<ImageView
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_margin="10dp"
android:scaleType="center"
android:background="#FFEEEE"
android:src="@drawable/ic_male"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Custom UnscaledImageView:"
android:textAppearance="?android:attr/textAppearanceLarge"/>
<com.sampleapp.widget.UnscaledImageView
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_margin="10dp"
android:scaleType="center"
android:background="#FFEEEE"
android:src="@drawable/ic_female"/>
<com.sampleapp.widget.UnscaledImageView
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_margin="10dp"
android:scaleType="center"
android:background="#FFEEEE"
android:src="@drawable/ic_male"/>
</LinearLayout>
现在更清楚了吗?这就是我想要做的,而且效果很好,除了一个小的性能问题......现在让我发布我用于此类自定义组件的代码:
attrs.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="UnscaledImageView">
<attr name="android:src" />
</declare-styleable>
</resources>
UnscaledImageView.java:
public class UnscaledImageView extends ImageView {
private int mDeviceDensityDpi;
public UnscaledImageView(Context context) {
super(context);
mDeviceDensityDpi = getResources().getDisplayMetrics().densityDpi;
}
public UnscaledImageView(Context context, AttributeSet attrs) {
super(context, attrs);
mDeviceDensityDpi = getResources().getDisplayMetrics().densityDpi;
TypedArray styledAttrs = context.obtainStyledAttributes(attrs, R.styleable.UnscaledImageView);
int resourceId = styledAttrs.getResourceId(R.styleable.UnscaledImageView_android_src, 0);
if(resourceId != 0) {
setUnscaledImageResource(resourceId);
}
styledAttrs.recycle();
}
public void setUnscaledImageResource(int resId) {
setImageBitmap(decodeBitmapResource(resId));
}
@SuppressWarnings("deprecation")
public void setUnscaledBackgroundResource(int resId) {
BitmapDrawable drawable = new BitmapDrawable(null, decodeBitmapResource(resId));
drawable.setTargetDensity(mDeviceDensityDpi);
drawable.setGravity(Gravity.CENTER);
setBackgroundDrawable(drawable);
}
private Bitmap decodeBitmapResource(int resId) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inDensity = mDeviceDensityDpi;
return BitmapFactory.decodeResource(getResources(), resId, options);
}
}
所以,如果 UnscaledImageView 视图用于 XML 布局或直接在代码中初始化,则此类将执行此操作。我还提供了 2 种方法,因此可以在代码中更改图像,同时防止其被拉伸。如您所见,这些方法只获取资源id,到目前为止我还没有觉得需要直接使用drawables或bitmaps。
现在我遇到的真正问题...
如果这个类在某些布局中用作单个图像视图,没问题,它只解码一个图像。但是,如果它在GridView 中使用,其中可能有 40 个图标(我从我的 xhdpi 设备上运行的应用程序实际发生的情况中获取这个值)同时可见,滚动GridView 将非常很慢,因为 decodeBitmapResource() 正在为每张图片调用 BitmapFactory.decodeResource()。
这是我的问题,也是我的问题。 我怎样才能优化它?如果可能的话……
【问题讨论】:
-
我真的认为不需要自定义
ImageView,因为您可以使用标准的ScaleType -
@Rajesh 不,这与此类所做的不同。我开发了这个类,因为标准
ImageView中的任何一个选项都没有达到我想要的效果(尤其是ScaleType属性)。 -
也许我没有抓住重点,但是如何创建一个重心的布局 XML 并包含一个将 scaleType 设置为 center 的 ImageView?您能否分享您的 GridView 布局和适配器的 getView 代码?
-
@Rajesh 同样,这与我在这门课上所做的不一样。
GridView布局和适配器无关。GridView是我在我的应用程序上使用的,但我还不如在LinearLayout上有一堆单独的ImageView,问题会是一样的。我真的不知道如何比我在这个问题上所做的更好地解释这个问题。我花时间把它写好……如果你还是不明白,我不知道该怎么说。 -
我刚记得的一件事我错过了解释......我举了一个例子,在 mdpi/hdpi 文件夹中有一些图像,但在 xhdpi 上没有。但在某些其他情况/图像中,特定图像也可能存在于 xhdpi 文件夹中。这个自定义
ImageView适应了这一点。仅使用 XML 和标准ImageView是无法做到这一点的。
标签: android optimization android-imageview custom-component android-gridview