android 2.3.3中自定义ListView(Canvas上的绘图项)的神秘行为

时间:2014-08-15 17:46:23

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

我正在创建自定义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项目的定位和调整大小出现了问题:位图不会调整大小以查看&#39 ; onDraw中的s大小,当我们单击ListView或滚动它并释放时。

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

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

为什么会发生这种情况?我们如何解决这个问题?

1 个答案:

答案 0 :(得分:0)

好的,我发现了如何在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);
}

对于旧版本使用@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 - Matrix,b - 我们的位图。