I am working on my first "professional" (ie, full-functional, bug-free, presentable) Android application, and I'm having some problems with Android layouts.
In particular, I have a gridView that I have inflated with a layout that has an ImageView, a TextView, and a hidden TextView (visibility set to "gone").
I have an "Image not found" image that is 115 x 115. The other images ("found") are similarly 115 x 115. They're all JPEGs.
The problem is that nothing's lining up. The text is constrained to under 17 characters. So I would think that the images being the same size and the text being the same size, the cells would be the same size and the grid would line up ... but noooo ;)
See here for how it looks now and here for how it looks with relative layout.
Both this and this suggest using a RelativeLayout.
The gridview:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<GridView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/gridView"
android:numColumns="auto_fit"
android:gravity="top"
android:layout_gravity="top"
android:padding="10dp"
android:verticalSpacing="10dp"
android:horizontalSpacing="10dp"
android:columnWidth="50dp"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
</GridView>
</LinearLayout>
The cell:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/widget44"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_gravity="top"
android:gravity="top">
<ImageView
android:id="@+id/icon_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="top"
android:layout_gravity="top">
</ImageView>
<TextView
android:id="@+id/icon_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView"
android:gravity="center_horizontal"
android:textColorHighlight="#656565">
</TextView>
<TextView
android:id="@+id/full_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
android:layout_gravity="top" >
</TextView>
</RelativeLayout>
So ... I might have one thing wrong or several, to be sure. But I could use your help. Thanks.
EDIT: Someone suggested I post my adapter code, so here it is.
First, the gridview activity:
package com.buildingfive.sharealike;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.database.Cursor;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.GridView;
import android.widget.ListAdapter;
import android.widget.TextView;
import com.buildingfive.R;
public class BrowseSearchProducts extends Activity {
GridView gridView;
Cursor cursor;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.browse_search);
//get gridview data from db
DBHelper db = new DBHelper(this);
//this cursor is never really closed, everywhere I tried, GPF
cursor = db.getReadableDatabase().rawQuery("SELECT _id, Title, Image FROM products;", null);
cursor.moveToFirst();
//populate gridview
gridView = (GridView) findViewById(R.id.gridView);
ListAdapter listAdapter = new ImageAdapter(this, cursor);
((ImageAdapter) listAdapter).setCount(cursor.getCount());
gridView.setAdapter(listAdapter);
gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
TextView vText = (TextView) v.findViewById(R.id.full_text);
String strCaption = ((TextView) vText).getText().toString();
Intent intent = new Intent(BrowseSearchProducts.this, ShowDetails.class);
intent.putExtra("search", strCaption);
startActivity(intent);
}
});
}
@Override
protected void onDestroy() {
cursor.close();
this.finish();
super.onDestroy();
}
}
Now the custom ImageAdapter:
package com.buildingfive.sharealike;
import android.content.Context;
import android.database.Cursor;
import android.graphics.BitmapFactory;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import com.buildingfive.R;
public class ImageAdapter extends BaseAdapter {
Context mContext;
Cursor mCursor;
int mCount;
public static final int ACTIVITY_CREATE = 10;
public ImageAdapter(Context c, Cursor cursor){
mContext = c;
mCursor = cursor;
}
public void setCount(int nCount) {
this.mCount = nCount;
}
@Override
public int getCount() {
return mCount;
}
//also required
public Object getItem(int position) {
//should return the actual object at the specified position in our Adapter
return mCursor.getString(1);
}
//required
public long getItemId(int position) {
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View vwIconPlusCaption;
String strCaption = mCursor.getString(1);
String strFull = strCaption;
if (strCaption == "")
return null;
//The Beckham Experiment: Blah Blah Blah 2ndary Tagline
if (strCaption.indexOf(":") > -1)
strCaption = strCaption.split(":")[0].toString();
else
if (strCaption.length() >= 17)
strCaption = strCaption.substring(0, 17);
if(convertView == null){
LayoutInflater li;
li = LayoutInflater.from(mContext);
//icon_plus_caption is loaded into a view
vwIconPlusCaption = li.inflate(R.layout.icon_plus_caption, null);
TextView tv = (TextView) vwIconPlusCaption.findViewById(R.id.icon_text);
//the view's caption set here
tv.setText(strCaption);
TextView fullText = (TextView) vwIconPlusCaption.findViewById(R.id.full_text);
//passes the full title in a hidden ("gone") textview
fullText.setText(strFull);
ImageView iv = (ImageView) vwIconPlusCaption.findViewById(R.id.icon_image);
byte[] bb = mCursor.getBlob(2);
if (bb == null) {
//image not found
iv.setImageResource(R.drawable.not_found);
} else {
iv.setImageBitmap(BitmapFactory.decodeByteArray(bb, 0, bb.length));
}
if (position + 1 < mCount)
mCursor.moveToNext();
}
else
{
vwIconPlusCaption = convertView;
}
return vwIconPlusCaption;
}
}
EDIT: SOLVED: SOLUTION IS AS FOLLOWS:
For some reason, the sizes differ when pulling all the images from SQL lite VS the "not found" image from android resources. See this link for more info.
The line I added was:
iv.setImageBitmap(Bitmap.createScaledBitmap(bitmap, 115, 115, true));
... in order to force the size of the android drawable to 115 x 115.
Thanks for everyone who tried to pitch in.