Archive for July, 2010


When an ImageView scales its source image to fit inside its bounds, by default it scales by width and keeps aspect ratio. Great, but it doesn’t reduce the height of the ImageView to compensate, so you end up with large blank areas above/below the image to compensate. Two things need to be done to fix this:

  1. add android:anyDensity=”true” to your manifest (you should be pre-scaling these images based on dip anyway)
  2. Log your bitmap.getHeight()/Width() and ImageView.getMeasuredHeight()/Width() and adjust your scaling so that it’s not getting scaled at all – that way, the height shouldn’t push out the imageview.
Advertisements

ListViews are, generally, pretty boring. If we’re displaying some kind of image-based data, we can bind ImageViews into them – and to make them slightly prettier, round off the top/bottom edges of the list. This works especially well with subheaded-lists.

To do this, I grabbed some code from http://www.ruibm.com/?p=184 that rounds all edges of a bitmap and modified it.

public Bitmap getRoundedCornerBitmap(Bitmap bitmap) 
{
	final int color = 0xff424242;
	final Paint paint = new Paint();
	final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
	Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Config.ARGB_8888);
	Canvas canvas = new Canvas(output);

	// the float array passed to this function defines the x/y values of the corners
	// it starts top-left and works clockwise
	// so top-left-x, top-left-y, top-right-x etc
	// a curve of 10.0f will typically work pretty well for a larger image
	RoundRectShape rrs = new RoundRectShape(
			new float[] {0, 0, 0, 0, 0, 0, 0, 0}, 
						null, null);
	
	canvas.drawARGB(0, 0, 0, 0);
	paint.setAntiAlias(true);
	paint.setColor(color);
	rrs.resize(bitmap.getWidth(), bitmap.getHeight());
	rrs.draw(canvas, paint);
	
	paint.setXfermode(new PorterDuffXfermode(android.graphics.PorterDuff.Mode.SRC_IN));
	canvas.drawBitmap(bitmap, rect, rect, paint);
	return output;
}

With this, we can do something like the below.

private List<something> mData;

public SomeAdapter(...)
{
	super(...);
	mData = data;
}

@Override
public View getView(int position, View convertView, ViewGroup parent)
{
	ViewHolder holder;
	
	if (convertView == null)
	{
		// ...
	}
	else
	{
		// ...
	}
	
	// get Bitmap b from a file or somewhere (it's our image for this list item)
	
	// i modified the function again to be 0 = top edges rounded
	if (position == 0)
		b = getRoundedCornerBitmap(b, 0);

	// no else, our item could be the only one in its list and hence may need rounding on both edges

	if (position == mData.size() - 1)
		b = getRoundedCornerBitmap(b, 1); // and 1 is bottom

The official android documentation suggests using getContext().getResources().getDisplayMetrics().density; to get the density of the device in order to scale images, etc, to a size appropriate to the device being used. This doesn’t seem to work, returning a value of 1.0f on every emulator (and my desire) across all versions. Alas, there’s another place to actually find it.

DisplayMetrics dm = new DisplayMetrics();
mActivity.getWindowManager().getDefaultDisplay().getMetrics(dm);

int pixelHeight = (int) (dipHeight * dm.density);