I have Staggered Grid view in which each item contains an image and text. Have a look at this
Below code is item layout xml. DynamicHeightImageView is extended ImageView which is use to change height of image. Here I have tried to set
android:layout_width="fill_parent"
But I think it is not working.
<?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:background="#drawable/background_card"
android:orientation="vertical" >
<com.etsy.android.grid.util.DynamicHeightImageView
android:id="#+id/image"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:src="#drawable/ic_launcher"
android:gravity="center" />
<TextView
android:id="#+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="4dp"
android:paddingLeft="8dp"
android:textColor="#ED430F"
android:paddingRight="8dp"
android:paddingTop="4dp"
android:textSize="15sp"
android:typeface="sans" />
<TextView
android:id="#+id/description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="right"
android:paddingBottom="8dp"
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:paddingTop="4dp"
android:textSize="12sp"
android:textColor="#848484"
android:textStyle="italic" />
</LinearLayout>
DynamicHeightImageView class has following code
public class DynamicHeightImageView extends ImageView {
private double mHeightRatio;
public static float radius = 2.0f;
Path clipPath = new Path();
RectF rect = new RectF(0, 0, this.getWidth(), this.getHeight());
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
public DynamicHeightImageView(Context context, AttributeSet attrs) {
super(context, attrs);
if (Build.VERSION.SDK_INT < 18) {
this.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
}
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
public DynamicHeightImageView(Context context) {
super(context);
if (Build.VERSION.SDK_INT < 18) {
this.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
}
public void setHeightRatio(double ratio) {
if (ratio != mHeightRatio) {
mHeightRatio = ratio;
requestLayout();
}
}
public double getHeightRatio() {
return mHeightRatio;
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (mHeightRatio > 0.0) {
// set the image views size
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = (int) (width * mHeightRatio);
setMeasuredDimension(width, height);
}
else {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
#Override
protected void onDraw(Canvas canvas) {
rect.left = 0;
rect.top = 0;
rect.right = this.getWidth();
rect.bottom = this.getHeight();
clipPath.addRoundRect(rect, radius, radius, Path.Direction.CW);
canvas.clipPath(clipPath);
super.onDraw(canvas);
}
}
Below code is Grid View Adapter class. This actually binds data with GridView. Here I have also tried to set image view width to fill the parent but it is not working result is the same. Can anyone tel me where I am making mistake?
public class DataAdapter extends ArrayAdapter<Video> {
Activity activity;
int resource;
List<Video> datas;
public DataAdapter(Activity activity, int resource, List<Video> objects) {
super(activity, resource, objects);
this.activity = activity;
this.resource = resource;
this.datas = objects;
}
#SuppressWarnings("deprecation")
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
final DealHolder holder;
if (row == null) {
LayoutInflater inflater = activity.getLayoutInflater();
row = inflater.inflate(resource, parent, false);
holder = new DealHolder();
holder.image = (DynamicHeightImageView)row.findViewById(R.id.image);
holder.title = (TextView)row.findViewById(R.id.title);
holder.date = (TextView)row.findViewById(R.id.description);
row.setTag(holder);
}
else {
holder = (DealHolder) row.getTag();
}
final Video data = datas.get(position);
Picasso.with(this.getContext())
.load(data.getImgURL())
.into(holder.image);
holder.image.setHeightRatio(getRandomHeight());
holder.image.getLayoutParams().width = LayoutParams.FILL_PARENT;
holder.image.requestLayout();
holder.title.setText(data.getTitle());
holder.date.setText(data.getUploadedDate().toGMTString().subSequence(0, 16));
return row;
}
static class DealHolder {
DynamicHeightImageView image;
TextView title;
TextView date;
}
private float getRandomHeight(){
ArrayList<Float> lista = new ArrayList<Float>();
lista.add((float) 0.5);
lista.add((float) 1.0);
lista.add((float) 0.75);
lista.add((float) 1.5);
Collections.shuffle(lista);
return lista.get(0);
}
}
Related
I am trying to set a dynamic width and height of my GridView's items, this is my code:
class GridAdapter extends BaseAdapter {
private Context context;
private GridAdapter(Context context, List<ParseObject> objects) {
super();
this.context = context;
}
// CONFIGURE CELL
#Override
public View getView(int position, View cell, ViewGroup parent) {
if (cell == null) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
cell = inflater.inflate(R.layout.cell_post_search, null);
}
//-----------------------------------------------
// MARK - INITIALIZE VIEWS
//-----------------------------------------------
ImageView postImg = cell.findViewById(R.id.cpsPostImg);
ImageView videoicon = cell.findViewById(R.id.cpsVideoIcon);
...
return cell;
}
#Override public int getCount() { return postsArray.size(); }
#Override public Object getItem(int position) { return postsArray.get(position); }
#Override public long getItemId(int position) { return position; }
}
// Set Adapter
postsGridView.setAdapter(new GridAdapter(ctx, postsArray));
// Set number of Columns accordingly to the device used
float scalefactor = getResources().getDisplayMetrics().density * screenW/3; // LET'S PRETEND MY screenW = 720, this value whoudl, be 240, which is the width i need for my cell
int number = getWindowManager().getDefaultDisplay().getWidth();
int columns = (int) ((float) number / scalefactor);
postsGridView.setNumColumns(columns);
Log.i(Configurations.TAG, "SCALE FACTOR: " + scalefactor);
And here's my custom cell_post_search.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:id="#+id/cpsCellLayout"
android:layout_width="150dp"
android:layout_height="150dp"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true">
<ImageView
android:id="#+id/cpsPostImg"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:background="#c1c1c1"
android:scaleType="centerCrop"/>
<ImageView
android:id="#+id/cpsVideoIcon"
android:layout_width="44dp"
android:layout_height="44dp"
android:layout_alignEnd="#+id/cpsPostImg"
android:layout_alignParentTop="true"
android:layout_marginRight="5dp"
android:layout_marginTop="5dp"
android:visibility="invisible"
app:srcCompat="#drawable/play_butt"/>
<ImageView
android:id="#+id/cpsWhiteFrame"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:srcCompat="#drawable/white_frame"/>
</RelativeLayout>
</RelativeLayout>
I get 480.0 as scale factor in my Logcat, which is not the right size I need (in my case it should be 240). Anyway, I've also tried to do this:
int columns = (int) ((float) number / (scalefactor/2));
So the scalefactor = 240, but it doesn't matter, because I need my cell's item to be square size, so basically: WIDTH = screenWidth/3, HEIGHT = screenWidth/3.
It doesn't work properly, my GridView shows 3 columns but cells get stretched in width - height looks fine - as shown here:
Is there a way to edit my code and make cells size correctly, as square images, 3 columns, based on the device size?
Try This
class GridAdapter extends BaseAdapter {
private Context context;
private GridAdapter(Context context, List<ParseObject> objects) {
super();
this.context = context;
}
// CONFIGURE CELL
#Override
public View getView(int position, View cell, ViewGroup parent) {
if (cell == null) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
cell = inflater.inflate(R.layout.cell_post_search, null);
}
//-----------------------------------------------
// MARK - INITIALIZE VIEWS
//-----------------------------------------------
ImageView postImg = cell.findViewById(R.id.cpsPostImg);
ImageView videoicon = cell.findViewById(R.id.cpsVideoIcon);
DisplayMetrics displayMetrics = new DisplayMetrics();
((Activity) mContext).getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
int width = displayMetrics.widthPixels;
postImg.getLayoutParams().height = width / 3;
...
return cell;
}
#Override public int getCount() { return postsArray.size(); }
#Override public Object getItem(int position) { return postsArray.get(position); }
#Override public long getItemId(int position) { return position; }
}
Also, in your XML layout, add android:numColumns="3":
<GridView
android:id="#+id/upPostsGridView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:numColumns="3"/>
I've created a custom RelativeLayout that has two ImageView in it, one on top of the other, The first one is supposed to show the user selected image and the second on is shown up after he selected and acts as a delete button (small X icon), the problem that i have is even at the start of the application this custom view is invisible, but i can still click on it. and if i use a background for it i can see it.
Here is my Custom View class and XML
public class ImageViewWithIcon extends RelativeLayout{
public ImageView image, icon;
private final Context context;
public ImageViewWithIcon(final Context context)
{
super(context);
this.context = context;
}
public ImageViewWithIcon(final Context context, final AttributeSet attrs)
{
super(context, attrs);
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.image_view_with_icon, this, true);
RelativeLayout rl = (RelativeLayout) getChildAt(0);
icon = (ImageView) findViewById(R.id.ImageViewWithIcon_icon);
image = (ImageView) findViewById(R.id.ImageViewWithIcon_image);
// image.setLayoutParams(new LayoutParams(400, 400));
this.context = context;
}
public ImageViewWithIcon(final Context context, final AttributeSet attrs, final int defStyle)
{
super(context, attrs, defStyle);
this.context = context;
}
#Override
protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec)
{
Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.drawable.new_message_picture_button);
int width;
if (getLayoutParams().width == android.view.ViewGroup.LayoutParams.WRAP_CONTENT)
width = bmp.getWidth();
else
if (getLayoutParams().width == android.view.ViewGroup.LayoutParams.MATCH_PARENT || getLayoutParams().width == android.view.ViewGroup.LayoutParams.FILL_PARENT)
width = MeasureSpec.getSize(widthMeasureSpec);
else
width = getLayoutParams().width;
int height = 100;
if (getLayoutParams().height == android.view.ViewGroup.LayoutParams.WRAP_CONTENT)
height = bmp.getHeight();
else
if (getLayoutParams().height == android.view.ViewGroup.LayoutParams.MATCH_PARENT || getLayoutParams().height == android.view.ViewGroup.LayoutParams.FILL_PARENT)
height = MeasureSpec.getSize(heightMeasureSpec);
else
height = getLayoutParams().height;
bmp.recycle();
setMeasuredDimension(width | MeasureSpec.EXACTLY, height | MeasureSpec.EXACTLY);
}}
<merge xmlns:android="http://schemas.android.com/apk/res/android" >
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<ImageView
android:id="#+id/ImageViewWithIcon_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="centerCrop"
android:background="#drawable/new_message_picture_button" />
<ImageView
android:id="#+id/ImageViewWithIcon_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="#id/ImageViewWithIcon_image"
android:visibility="visible"
android:src="#drawable/new_message_close_picture"/>
</RelativeLayout>
</merge>
The first line in onMessure has bmp with width and height of 234px
even if I create a method like setImage() to call it from the Activity, the image is set but it is still invisible.
Do you mean?
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<ImageViewWithIcon
android:id="#+id/ImageViewWithIcon_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="centerCrop"
android:background="#drawable/new_message_picture_button" />
<ImageViewWithIcon
android:id="#+id/ImageViewWithIcon_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="#id/ImageViewWithIcon_image"
android:visibility="visible"
android:src="#drawable/new_message_close_picture"/>
I am having trouble in getting the GridView content height programmatically since I am placing it inside a ScrollView, I just need to stretch the GridView height dynamically by getting its content height in PIXELS. Here's what I did:
#Override
public void onWindowFocusChanged(boolean hasFocus)
{
// TODO Auto-generated method stub
super.onWindowFocusChanged(hasFocus);
System.out.println("...111Height..."+gridView.getMeasuredWidth());
}
but I want to obtain the value inside OnCreate so that I can feed it to layoutParams.height in:
GridView gridView = (GridView) findViewById(R.id.gridview_module);
ViewGroup.LayoutParams layoutParams = gridView.getLayoutParams();
layoutParams.height = convertDpToPixels(iDontKnowWhatToPutHere, this);
gridView.setLayoutParams(layoutParams);
and the method to convert from pixels to dp:
public static int convertDpToPixels(float dp, Context context) {
Resources resources = context.getResources();
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp,
resources.getDisplayMetrics());
}
EDIT:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/mainLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context=".SecondActivity" >
<ScrollView
android:id="#+id/scrollview"
android:layout_width="match_parent"
android:layout_height="0"
android:layout_weight="1"
android:fillViewport="true"
android:scrollbars="none" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="#+id/tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/hello_world" />
<com.example.ExpandableHeightGridView
android:id="#+id/gridview_module"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_below="#id/tv"
android:layout_weight="1"
android:gravity="center"
android:horizontalSpacing="20dp"
android:numColumns="3"
android:stretchMode="columnWidth"
android:verticalSpacing="10dp" />
<Button
android:id="#+id/dial_phone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#id/gridview_module"
android:onClick="dialPhone"
android:text="Dial Phone" />
</LinearLayout>
</ScrollView>
To achieve this you need to create CustomGridview like this
public class CustomGridView extends GridView {
private int old_count;
private android.view.ViewGroup.LayoutParams params;
private boolean isExpandFully = false;
private int verticleSpacing = 4;
private int noOfCollumns = 1;
public int getNumColumns() {
return noOfCollumns;
}
public void setNoOfCollumns(int noOfCollumns) {
this.noOfCollumns = noOfCollumns;
}
public int getVerticleSpacing() {
return verticleSpacing;
}
public void setVerticleSpacing(int verticleSpacing) {
this.verticleSpacing = verticleSpacing;
}
public void setExpandFully(boolean isExpandFully) {
this.isExpandFully = isExpandFully;
}
public CustomGridView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public CustomGridView(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs);
}
public CustomGridView(Context context) {
super(context);
init(null);
}
private void init(AttributeSet attrs) {
if (attrs != null) {
String namespace = "http://schemas.android.com/apk/res/android";
noOfCollumns = attrs.getAttributeIntValue(namespace, "numColumns", 1);
}
}
#Override
protected void onDraw(Canvas canvas) {
setVerticalSpacing(getVerticleSpacing());
if (isExpandFully) {
try {
if (getCount() != old_count) {
old_count = getCount();
params = getLayoutParams();
int len = (getCount() % getNumColumns() == 0 ? getCount() / getNumColumns() : getCount() / getNumColumns() + 1);
params.height = 0;
for (int i = 0; i < len; i++) {
params.height = params.height + (old_count > 0 ? getChildAt(0).getHeight() + getVerticleSpacing() : 0);
}
params.height += 10;
setLayoutParams(params);
}
} catch (Exception e) {
}
}
super.onDraw(canvas);
}
}
how to use
CustomGridView myGridview = (CustomGridView)findViewById(R.id.customGridview);
myGridview.setExpandFully(true);
I need to create a custom ListView item with a TextView and a colored rectangle.
To do it I have an ArrayAdapter:
public class JobQuickListAdapter extends ArrayAdapter<Job>{
private int resource;
public JobQuickListAdapter(Context context, int resource, List<Job> items) {
super(context, resource, items);
this.resource = resource;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
JobTagView jobView;
Job item = getItem(position);
String jobTitle = item.getTitle();
if (convertView == null) {
jobView = new JobTagView(getContext());
String inflater = Context.LAYOUT_INFLATER_SERVICE;
LayoutInflater vi = (LayoutInflater)getContext().getSystemService(inflater);
vi.inflate(resource, jobView, true);
} else {
jobView = (JobTagView) convertView;
}
jobView.setColor(Color.BLUE);
TextView jobTitleText = (TextView)jobView.findViewById(R.id.jobItemTitle);
jobTitleText.setText(jobTitle);
return jobView;
}
}
And my Custom View extending from LinearLayout:
public class JobTagView extends LinearLayout{
private Paint paintOrig;
private RectF originRect;
private boolean pathCreated;
private int color;
public JobTagView(Context context) {
super(context);
initJobTag();
}
public JobTagView(Context context, AttributeSet attrs) {
super(context, attrs);
initJobTag();
}
private void initJobTag(){
setWillNotDraw(false);
paintOrig = new Paint();
paintOrig.setStyle(Paint.Style.FILL);
pathCreated = false;
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
if (!pathCreated){
float hR = h * 14 / 100;
float wR = w * 2 / 100;
originRect = new RectF(0, hR, wR, h - hR);
pathCreated = true;
}
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawRect(originRect, paintOrig);
}
public int getColor() {
return color;
}
public void setColor(int color) {
paintOrig.setColor(color);
this.color = color;
this.invalidate();
}
}
And the layout:
<com.sinPlanB.jobSniffer.utils.JobTagView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res/com.sinPlanB.jobSniffer.utils"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_margin="5dp"
android:background="#drawable/job_tab_search">
<TextView android:id="#+id/jobItemTitle"
android:textIsSelectable="true"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:lines="2"
android:textSize="16sp"/>
</com.sinPlanB.jobSniffer.utils.JobTagView>
My problem comes when the colored rectangle is drawn, because the rectangle seems to be drawn several times and with a small displacement each time. A first black rectangle in a right position and a wrong blue rectangle (the one created after changing the rectangle color --> jobView.setColor(Color.BLUE)) totally displaced.
What am I doing wrong? Is there any tutorial about drawing Custom Items in a List View?
I have a ListPopupWindow that is being populated from a custom adapter. The custom xml consists of 2 textviews and a LinearLayout. The custom adapter populates the textviews and instantiates a custom view that draws a thumbnail sized vector based graphic. The custom view is then added to the Linear Layout.
The problem is that the first row displayed always has the wrong graphic displayed. It is sometimes the graphic from another row, sometimes half of it is the correct graphic, half from the wrong row. I've also noticed that if the list has enough rows in it to scroll, the items at the bottom of the list have the same problem when scrolling.
Has anyone else experienced this?
Custom List Adapter:
public class PageSearchListAdapter extends SimpleCursorAdapter
{
int _height = 130;
int _width = 130;
Cursor c;
Context context;
// Constructor, here we store any parameters we need in class variables
//
public PageSearchListAdapter(Context context,
int layout,
Cursor c,
String[] from,
int[] to)
{
super(context, layout, c, from, to);
this.c = c;
this.context=context;
}
// Main view method - the views in query_list_item are populated here
//
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
// Make sure we have a view to work with
//
if(convertView == null)
convertView = View.inflate(context, R.layout.query_list_item, null);
View row = convertView;
// go to the correct row in the cursor
//
c.moveToPosition(position);
// Get the views that need populating
//
TextView PageNum = (TextView) convertView.findViewById(R.id.Page_Num);
LinearLayout pic = (LinearLayout) convertView.findViewById(R.id.Page_Canvas);
TextView Date = (TextView) convertView.findViewById(R.id.Page_Date);
// Set the values
//
PageNum.setText(c.getString(c.getColumnIndex("PageNum")));
Date.setText(c.getString(c.getColumnIndex("Timestamp")));
List<Point> Vectors = new ArrayList<Point>();
byte[] asBytes = c.getBlob(c.getColumnIndex("Vectors"));
..
.. removed code to Convert Blob to array of 'Vector' records ...
..
// Draw the page
//
NotePadPage npPage = new NotePadPage(context, Vectors);
npPage.setLayoutParams(new LayoutParams(_width, _height));
pic.addView(npPage);
return(row);
}
}
NotePadPage class:
// Adapter to display a custom list item in a list view
//
public class NotePadPage extends View
{
int _height = 130;
int _width = 130;
Bitmap _bitmap;
Canvas _canvas;
Paint _paint;
List<Point> _Vectors = new ArrayList<Point>();
public NotePadPage(Context context, List<Point> Vectors)
{
super(context);
_Vectors = Vectors;
_paint = new Paint();
_paint.setColor(Color.WHITE);
_paint.setStyle(Paint.Style.STROKE);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
_height = View.MeasureSpec.getSize(heightMeasureSpec);
_width = View.MeasureSpec.getSize(widthMeasureSpec);
setMeasuredDimension(_width, _height);
_bitmap = Bitmap.createBitmap(_width, _height, Bitmap.Config.ARGB_8888);
_canvas = new Canvas(_bitmap);
}
#Override
protected void onDraw(Canvas canvas)
{
float yRatio = 1092/ _height;
float xRatio = 800 / _width;
Point lastPoint = null;
for (Point point : _Vectors)
{
switch (point.Type)
{
case Start:
{
lastPoint = point;
break;
}
case Midpoint:
case End:
{
canvas.drawLine(lastPoint.x / xRatio, lastPoint.y/ yRatio, point.x / xRatio, point.y/ yRatio, _paint);
lastPoint = point;
}
}
}
}
}
Referenced Classes:
public class Point
{
public float x, y;
public PointType Type;
}
public enum PointType
{
Start,
Midpoint ,
End;
}
XML for List row:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center_vertical|center_horizontal" >
<TextView
android:id="#+id/Page_Num"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical|center_horizontal"
android:layout_marginRight="5dp"
android:text="1"
android:textAppearance="?android:attr/textAppearanceMedium" />
<LinearLayout
android:id="#+id/Page_Canvas"
android:layout_width="130dip"
android:layout_height="130dip"
android:gravity="center_vertical|center_horizontal"
android:layout_toRightOf="#id/Page_Num">
</LinearLayout>
<TextView
android:id="#+id/Page_Date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical|center_horizontal"
android:layout_marginLeft="5dp"
android:text="Medium Text"
android:textAppearance="?android:attr/textAppearanceMedium"
android:layout_toRightOf="#id/Page_Canvas">
</TextView>
</RelativeLayout>