【问题标题】:Mysterious behavior of custom ListView (drawing item on Canvas) in android 2.3.3android 2.3.3 中自定义 ListView(Canvas 上的绘图项)的神秘行为
【发布时间】:2014-08-15 17:46:23
【问题描述】:

我正在创建自定义 ListView。适配器:

public class CustomListEventsAdapter extends BaseAdapter {

private Context context;
private List<Map<String, String>> values;

public CustomListEventsAdapter(Context context, List<Map<String, String>> values) {
    this.context = context;
    this.values = values;
}

@Override
public int getCount() {
    return values.size();
}

@Override
public Object getItem(int position) {
    return values.get(position);
}

@Override
public long getItemId(int position) {
    return position;
}

@Override
public View getView(final int position, View convertView, ViewGroup parent) {
    final CustomItemForEventsList view = new CustomItemForEventsList(context, values.get(position), (long) position);

    int itemHeight;
    if (parent.getWidth() > parent.getHeight()) {
        itemHeight = parent.getHeight();
    } else {
        itemHeight = parent.getHeight() / 2;
    }

    view.setLayoutParams(new ListView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, itemHeight));
    return view;
}}

ListView 项目的自定义视图:

public class CustomItemForEventsList extends View {

private MainActivity context;
private Map<String,String> values;
private long id;

private Paint pMainText;

private int viewWidth;
private int viewHeight;
private boolean isLandscape;

private Bitmap backgroundBitmap;
private RectF bitmapSizes;
private RectF viewSizes;
private Matrix matrix;

public CustomItemForEventsList(final Context context, Map<String,String> values, long id) {
    super(context);
    this.context = (MainActivity) context;
    this.values = values;
    this.id = id;

    pMainText = new Paint(Paint.ANTI_ALIAS_FLAG);
    pMainText.setColor(Color.WHITE);
    pMainText.setTextAlign(Paint.Align.LEFT);

    bitmapSizes = new RectF();
    viewSizes = new RectF();
    matrix = new Matrix();
    loadBackgroundBitmap(values.get("url"));
}

private void loadBackgroundBitmap(final String url) {
    context.imageLoader.loadImage(url, new ImageSize(viewWidth, viewHeight), context.displayImageOptions, new ImageLoadingListener() {
        @Override
        public void onLoadingStarted(String s, View view) {
        }

        @Override
        public void onLoadingFailed(String s, View view, FailReason failReason) {
            // Log.d(Statics.LOG, "onLoadingFailed");
        }

        @Override
        public void onLoadingComplete(String s, View view, Bitmap bitmap) {
            backgroundBitmap = bitmap;
            invalidate();
        }

        @Override
        public void onLoadingCancelled(String s, View view) {
            // Log.d(Statics.LOG, "onLoadingCanceled");
            loadBackgroundBitmap(url);
        }
    });
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    viewWidth = MeasureSpec.getSize(widthMeasureSpec);
    viewHeight = MeasureSpec.getSize(heightMeasureSpec);
    isLandscape = viewWidth > viewHeight;

    viewSizes.set(0, 0, viewWidth, viewHeight);
}

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    canvas.drawARGB(255, 0, 0, 0);
    // Drawing view's background
    if (backgroundBitmap != null) {
        if (!backgroundBitmap.isRecycled()) {
            bitmapSizes.set(0, 0, backgroundBitmap.getWidth(), backgroundBitmap.getHeight());
            matrix.setRectToRect(viewSizes, bitmapSizes, Matrix.ScaleToFit.FILL);
            matrix.invert(matrix);
            canvas.drawBitmap(backgroundBitmap, matrix, null);
        }
    }
}}

在新的 Android 版本上一切正常(在 4.0、4.2、4.4 上测试),但在 2.3.3 中,ListView 项目的定位和调整大小出现问题:当我们点击时,位图不会在 onDraw 中调整为视图大小ListView 或滚动它并释放。

2.3.3 中的屏幕。这就是当我们按下 ListView,然后滚动,然后等待一段时间并释放时发生的情况(我希望在所有情况下都看到这种行为): http://s16.postimg.org/qvf26fb45/image.png

当我们单击 ListView 或滚动并释放时,通常会发生以下情况: http://s22.postimg.org/d7fd8quc1/image.png

为什么会发生,我们该如何解决?

【问题讨论】:

  • 将 RectFs 交换为 matrix.setRectToRect(bitmapSizes, viewSizes, ... 并删除 matrix.invert() 方法调用
  • 非常感谢@pskink!它解决了这个问题。但是我不明白为什么4.0和2.3.3之间的绘图机制有这样的差异,为什么会出现这个问题?
  • UPD:抱歉,实际上并没有解决。我看到,当我们使用带有标志 Matrix.ScaleToFit.FILL 的 matrix.setRectToRect 时,我们的图像会拉伸到视图并且它的比例变得错误:s12.postimg.org/y3u04k225/image.png 当我们使用 Matrix.ScaleToFit.START 或其他人离开时,位图适合视图:@ 987654324@ 但我希望位图放大以查看并保存其比例(位图两侧的部分将被裁剪)。有可能吗?
  • Matrix.ScaleToFit.FILL 不保留纵横比,您可能需要开始、结束或居中
  • 看起来我们不理解对方)我不想将Bitmap放在View中,我想要将Bitmap升级到View并将它放在View的中心(Bitmap的某些部分将裁剪)。而且我已经找到了解决方案。

标签: android listview android-2.3-gingerbread ondraw custom-view


【解决方案1】:

好的,我发现了如何在 Android 2.3.3 中解决这个问题。当然,我们可以在代码中查看 Android 的版本,并创建两个分支:旧版本和新版本。对于新版本,请使用 Matrix:

if (!backgroundBitmap.isRecycled()) {
        bitmapSizes.set(0, 0, backgroundBitmap.getWidth(), backgroundBitmap.getHeight());
        matrix.setRectToRect(viewSizes, bitmapSizes, Matrix.ScaleToFit.CENTER);
        matrix.invert(matrix);
        canvas.drawBitmap(backgroundBitmap, matrix, null);
}

对于旧版本使用方法,由 cmets 中的 @pskink 提出。但我不希望看到不同 Android 版本之间的任何差异(适合旧版本,裁剪新版本),所以我提供了另一种方式。

我们的目标是避免使用 Rects 和 Matrix 进行操作,它们看起来非常昂贵,并且在 Android 2.3.3 中绘制自定义 ListView 项目时给我们带来了一些错误。所以我们必须手动完成所有高档操作:

public class CustomItemForEventsList extends View {

private MainActivity context;

private int viewWidth;
private int viewHeight;

private Bitmap backgroundBitmap;
private Rect bitmapSizes;
private Rect preferedBitmapSizes;

public CustomItemForEventsList(final Context context, Map<String,String> values, long id) {
    super(context);
    this.context = (MainActivity) context;

    bitmapSizes = new Rect();
    preferedBitmapSizes = new Rect();
    loadBackgroundBitmap(values.get("url"));
}

private void loadBackgroundBitmap(final String url) {
    context.imageLoader.loadImage(url, new ImageSize(viewWidth, viewHeight), context.displayImageOptions, new ImageLoadingListener() {
        @Override
        public void onLoadingStarted(String s, View view) {
        }

        @Override
        public void onLoadingFailed(String s, View view, FailReason failReason) {
            // Log.d(Statics.LOG, "onLoadingFailed");
        }

        @Override
        public void onLoadingComplete(String s, View view, Bitmap bitmap) {
            backgroundBitmap = bitmap;
            invalidate();
        }

        @Override
        public void onLoadingCancelled(String s, View view) {
            // Log.d(Statics.LOG, "onLoadingCanceled");
            loadBackgroundBitmap(url);
        }
    });
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    viewWidth = MeasureSpec.getSize(widthMeasureSpec);
    viewHeight = MeasureSpec.getSize(heightMeasureSpec);
}

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    canvas.drawARGB(255, 0, 0, 0);
    // Drawing view's background
    if (backgroundBitmap != null) {
        if (!backgroundBitmap.isRecycled()) {
            bitmapSizes.set(0, 0, backgroundBitmap.getWidth(), backgroundBitmap.getHeight());
            setPreferedBitmapSizes();
            canvas.drawBitmap(backgroundBitmap, bitmapSizes, preferedBitmapSizes, null);
        }
    }
}

private void setPreferedBitmapSizes() {
    int instBmpWidth = backgroundBitmap.getWidth();
    int instBmpHeight = backgroundBitmap.getHeight();

    int newBmpWidth, newBmpHeight;
    newBmpWidth = viewWidth; newBmpHeight = viewWidth * instBmpHeight / instBmpWidth;

    if (viewHeight > newBmpHeight) {
        newBmpWidth = instBmpWidth * viewHeight / instBmpHeight; newBmpHeight = viewHeight;
        if (newBmpWidth == viewWidth) {
            preferedBitmapSizes.set(0, 0, newBmpWidth, newBmpHeight);
        } else {
            preferedBitmapSizes.set(-((newBmpWidth-viewWidth)/2), 0, viewWidth + ((newBmpWidth-viewWidth)/2), newBmpHeight);
        }
    } else {
        if (newBmpHeight == viewHeight) {
            preferedBitmapSizes.set(0, 0, newBmpWidth, newBmpHeight);
        } else {
            preferedBitmapSizes.set(0, -((newBmpHeight-viewHeight)/2), newBmpWidth, viewHeight + ((newBmpHeight-viewHeight)/2));
        }
    }
}}

现在问题解决了:

http://s29.postimg.org/hbv9d0z3b/image.png

更新:我们可以使用更简单的代码(感谢pskink,这是他的解决方案):

        m.reset();
        float scaleX = getWidth() / (float) b.getWidth();
        float scaleY = getHeight() / (float) b.getHeight();

        float scale = Math.max(scaleX, scaleY);
        m.postScale(scale, scale);
        float dx = (getWidth() - b.getWidth() * scale) / 2;
        float dy = (getHeight() - b.getHeight() * scale) / 2;
        m.postTranslate(dx, dy);
       
        canvas.drawBitmap(b, m, null);

其中 m - 矩阵,b - 我们的位图。

【讨论】:

  • 再次感谢您,这段代码看起来比我的好多了。我会在我的帖子中添加它。
猜你喜欢
  • 1970-01-01
  • 2013-03-27
  • 1970-01-01
  • 1970-01-01
  • 2011-06-22
  • 1970-01-01
  • 1970-01-01
  • 2012-05-05
相关资源
最近更新 更多