Ironically enough I stumbled on a problem when I answered another question
The problem is that if I add a RelativeLayout as a child of my ICGridLayout the children of that RelativeLayout does not get the RelativeLayout.LayoutParams. This goes for all kinds of layouts that I add to my ICGridLayout. I've read through the source code for both LinearLayout, RelativeLayout, AbsoluteLayout and ViewGroup but have not found anything that gives me a hint of where I do something wrong. I also watched the Romain Guy's guide to created a FlowLayout in the hopes of getting an answer, alas that did not happen.
EDIT
Added my layout.xml file. It seems as if the children respond to above, below, toLeftOf, toRightOf and margins but not other relative layout rules.
As you can see I use simple XML layout.
Even if they children respond to the above rules, the eclipse (and android studio) auto complete does not recognise the xml attributes.
END EDIT
My attrs.xml file:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="ICGridLayout_Layout">
<attr name="columns" format="integer"/>
<attr name="layout_left" format="integer"/>
<attr name="layout_top" format="integer"/>
<attr name="layout_right" format="integer"/>
<attr name="layout_bottom" format="integer"/>
<attr name="layout_col_span" format="integer"/>
<attr name="layout_row_span" format="integer"/>
<attr name="layout_spacing" format="dimension"/>
</declare-styleable>
</resources>
And my ICGridLayout.java file:
package com.risch.evertsson.iclib.layout;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.RemoteViews.RemoteView;
import com.risch.evertsson.iclib.R;
/**
* Created by johanrisch on 6/13/13.
*/
#RemoteView
public class ICGridLayout extends ViewGroup {
private int mColumns = 4;
private float mSpacing;
public ICGridLayout(Context context) {
super(context);
}
public ICGridLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs);
}
public ICGridLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(attrs);
}
private void init(AttributeSet attrs) {
TypedArray a = getContext().obtainStyledAttributes(
attrs,
R.styleable.ICGridLayout_Layout);
this.mColumns = a.getInt(R.styleable.ICGridLayout_Layout_columns, 3);
this.mSpacing = a.getDimension(R.styleable.ICGridLayout_Layout_layout_spacing, 0);
a.recycle();
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
if (changed) {
int width = (int) (r - l);
int side = width / mColumns;
int children = getChildCount();
View child = null;
for (int i = 0; i < children; i++) {
child = getChildAt(i);
LayoutParams lp = (LayoutParams) child.getLayoutParams();
int left = (int) (lp.left * side + mSpacing / 2);
int right = (int) (lp.right * side - mSpacing / 2);
int top = (int) (lp.top * side + mSpacing / 2);
int bottom = (int) (lp.bottom * side - mSpacing / 2);
child.layout(left, top, right, bottom);
}
}
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
measureVertical(widthMeasureSpec, heightMeasureSpec);
}
private void measureVertical(int widthMeasureSpec, int heightMeasureSpec) {
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int width = 0;
int height = 0;
if (widthMode == MeasureSpec.AT_MOST || widthMode == MeasureSpec.EXACTLY) {
width = MeasureSpec.getSize(widthMeasureSpec);
} else {
throw new RuntimeException("widthMeasureSpec must be AT_MOST or " +
"EXACTLY not UNSPECIFIED when orientation == VERTICAL");
}
View child = null;
int row = 0;
int side = width / mColumns;
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
child = getChildAt(i);
LayoutParams lp = (LayoutParams) child.getLayoutParams();
if (lp.bottom > row) {
row = lp.bottom;
}
int childHeight = (lp.bottom - lp.top)*side;
int childWidth = (lp.right-lp.left)*side;
int heightSpec = getChildMeasureSpec(heightMeasureSpec, 0, childHeight);
int widthSpec = getChildMeasureSpec(widthMeasureSpec, 0, childWidth);
// measureChild(child, widthMeasureSpec, heightMeasureSpec);
child.measure(widthSpec, heightSpec);
}
height = row * side;
// TODO: Figure out a good way to use the heightMeasureSpec...
setMeasuredDimension(width, height);
}
#Override
public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
return new ICGridLayout.LayoutParams(getContext(), attrs);
}
#Override
protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
return p instanceof ICGridLayout.LayoutParams;
}
#Override
protected ViewGroup.LayoutParams
generateLayoutParams(ViewGroup.LayoutParams p) {
return new ICGridLayout.LayoutParams(p);
}
protected ViewGroup.LayoutParams
generateLayoutParams(ViewGroup.MarginLayoutParams p) {
return new ICGridLayout.LayoutParams(p);
}
#Override
protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
return new LayoutParams();
}
public static class LayoutParams extends ViewGroup.MarginLayoutParams {
int right = 1;
int bottom = 1;
int top = 0;
int left = 0;
int width = -1;
int height = -1;
public LayoutParams() {
super(MATCH_PARENT, MATCH_PARENT);
top = 0;
left = 1;
}
public LayoutParams(int width, int height) {
super(width, height);
top = 0;
left = 1;
}
public LayoutParams(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(
attrs,
R.styleable.ICGridLayout_Layout);
left = a.getInt(R.styleable.ICGridLayout_Layout_layout_left, 0);
top = a.getInt(R.styleable.ICGridLayout_Layout_layout_top, 0);
right = a.getInt(R.styleable.ICGridLayout_Layout_layout_right, left + 1);
bottom = a.getInt(R.styleable.ICGridLayout_Layout_layout_bottom, top + 1);
height = a.getInt(R.styleable.ICGridLayout_Layout_layout_row_span, -1);
width = a.getInt(R.styleable.ICGridLayout_Layout_layout_col_span, -1);
if (height != -1) {
bottom = top + height;
}
if (width != -1) {
right = left + width;
}
a.recycle();
}
public LayoutParams(ViewGroup.LayoutParams params) {
super(params);
}
public LayoutParams(ViewGroup.MarginLayoutParams params) {
super(params);
}
}
}
My layout.xml file:
<com.risch.evertsson.iclib.layout.ICGridLayout
android:id="#+id/ICGridLayout1"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:spacing="4dp"
app:columns="4" >
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_bottom="8"
app:layout_left="0"
app:layout_right="4"
app:layout_top="0" >
<Button
android:id="#+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginLeft="90dp"
android:layout_marginTop="109dp"
android:text="Button" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:background="#ffffff"
android:layout_marginLeft="0dp"
android:centerHorizontal="true"
android:layout_below="#+id/button"
android:orientation="vertical" >
<Button
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginLeft="90dp"
android:layout_marginTop="109dp"
android:text="Button" />
</LinearLayout>
</RelativeLayout>
</com.risch.evertsson.iclib.layout.ICGridLayout>
I've spent at least 5 hours browsing SO and google in order to find an answer and that's why I'm writing my own question.
Thanks in advance.
--Johan Risch
Related
For some reason my custom viewgroup is not showing all children when i add weight to my Horizontalscrollview but it works perfect when i removed the weight here is my xml. Does anyone have any idea what is going on?
XML
<?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:orientation="vertical">
<LinearLayout
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">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="7"
android:orientation="vertical">
</LinearLayout>
<HorizontalScrollView
android:id="#+id/handScrollView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_weight="2"
android:background="#color/colorAccent">
<com.example.example.cardgame.bin.template.HandViewLayout
android:id="#+id/handView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#color/black_grey">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#color/cardview_light_background"
android:text="View1" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#color/cardview_dark_background"
android:text="View2" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#color/face_down"
android:text="View3" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#color/colorAccent"
android:text="View4" />
</com.example.example.cardgame.bin.template.HandViewLayout>
</HorizontalScrollView>
</LinearLayout>
</LinearLayout>
However when i set my Horizontal scrollview to wrap_content or match_parent, it works as desired, why is it not working when i set weight attribute?
Here is my Class HandViewLayout
public class HandViewLayout extends ViewGroup {
private int mLeftWidth;
public float coverCard = 0;
private int mRightWidth;
private final Rect mTmpContainerRect = new Rect();
private final Rect mTmpChildRect = new Rect();
public OnClickListenerViewGroup onClickListenerViewGroup;
public HandViewLayout(Context context) {
super(context);
setHorizontalScrollBarEnabled(true);
setVerticalScrollBarEnabled(true);
}
public void setCoverCard(float coverCard) {
this.coverCard = -Math.abs(coverCard);
}
public float getCoverCard() {
return this.coverCard;
}
public HandViewLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public HandViewLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public void setOnClickListenerViewGroup(OnClickListenerViewGroup onClickListenerViewGroup) {
this.onClickListenerViewGroup = onClickListenerViewGroup;
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
final int count = getChildCount();
// These are the far left and right edges in which we are performing layout.
int leftPos = getPaddingLeft();
int rightPos = r - l - getPaddingRight();
// This is the middle region inside of the gutter.
final int middleLeft = leftPos + mLeftWidth;
final int middleRight = rightPos - mRightWidth;
// These are the top and bottom edges in which we are performing layout.
final int parentTop = getPaddingTop();
final int parentBottom = b - t - getPaddingBottom();
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
final int width = child.getMeasuredWidth();
final int height = child.getMeasuredHeight();
final int index = i;
child.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
onClickListenerViewGroup.onClickListenerViewGroup(index);
}
});
if (i > 0) {
final View previousChild = getChildAt(i - 1);
mTmpContainerRect.left = middleLeft + lp.leftMargin + previousChild.getLeft() + previousChild.getWidth() + (int) coverCard;
mTmpContainerRect.right = middleRight - lp.rightMargin;
mTmpContainerRect.top = parentTop + lp.topMargin;
mTmpContainerRect.bottom = parentBottom - lp.bottomMargin;
} else {
mTmpContainerRect.left = middleLeft + lp.leftMargin;
mTmpContainerRect.right = middleRight - lp.rightMargin;
mTmpContainerRect.top = parentTop + lp.topMargin;
mTmpContainerRect.bottom = parentBottom - lp.bottomMargin;
}
// Use the child's gravity and size to determine its final
// frame within its container.
Gravity.apply(lp.gravity, width, height, mTmpContainerRect, mTmpChildRect);
// Place the child.
child.layout(mTmpChildRect.left, mTmpChildRect.top,
mTmpChildRect.right, mTmpChildRect.bottom);
}
}
#Override
protected boolean awakenScrollBars() {
return true;
}
#Override
protected int computeVerticalScrollExtent() {
return super.computeVerticalScrollExtent();
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int count = getChildCount();
mLeftWidth = 0;
mRightWidth = 0;
int maxHeight = 0;
int maxWidth = 0;
int childState = 0;
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
// Log.e("child Text", i + ": " + ((TextView) child).getText().toString());
if (child.getVisibility() != GONE) {
measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
// last one show all
if (i == getChildCount() - 1) {
maxWidth += child.getMeasuredWidth();
} else {
maxWidth += child.getMeasuredWidth() + coverCard;
}
Log.d("Spacer", "spacer, " + i + "," + maxWidth);
maxHeight = Math.max(maxHeight, child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin);
}
}
setMeasuredDimension(resolveSizeAndState(maxWidth, heightMeasureSpec, childState),
resolveSizeAndState(maxHeight, heightMeasureSpec,
childState));
}
#Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
return new HandViewLayout.LayoutParams(getContext(), attrs);
}
#Override
protected LayoutParams generateDefaultLayoutParams() {
return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
}
#Override
protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
return new LayoutParams(p);
}
#Override
protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
return p instanceof LayoutParams;
}
#Override
public boolean shouldDelayChildPressedState() {
return false;
}
public static class LayoutParams extends MarginLayoutParams {
public int gravity = Gravity.TOP | Gravity.START;
public static int POSITION_MIDDLE = 0;
public static int POSITION_LEFT = 1;
public static int POSITION_RIGHT = 2;
public int position = POSITION_MIDDLE;
public LayoutParams(Context c, AttributeSet attrs) {
super(c, attrs);
TypedArray atts = c.obtainStyledAttributes(attrs, R.styleable.HandViewLayout);
gravity = atts.getInt(R.styleable.HandViewLayout_android_layout_gravity, gravity);
position = atts.getInt(R.styleable.HandViewLayout_layout_position, position);
atts.recycle();
}
public LayoutParams(int width, int height) {
super(width, height);
}
public LayoutParams(MarginLayoutParams source) {
super(source);
}
public LayoutParams(ViewGroup.LayoutParams source) {
super(source);
}
}
}
Attributes xml
<declare-styleable name="HandViewLayout">
<attr name="layoutColor" format="color" />
<attr name="android:layout_gravity" />
<attr name="layout_position">
<enum name="middle" value="0" />
<enum name="left" value="1" />
<enum name="right" value="2" />
</attr>
</declare-styleable>
PIC
I would like to create a custom RelativeLayout that has two views in one row: one on the left side of the screen (android:layout_alignParentStart="true") and one on the right (android:layout_alignParentEnd="true"). The view on the right will grow toward the left view until it takes up all the space between the two views. Then it will move to a new line under the view on the left.
I have implemented a slightly modified version of Romain Guy's FlowLayout that extends RelativeLayout. However, this class seems to ignore the RelativeLayout's align properties and just sticks the views right next to each other. Is there a way to implement a such a layout that will anchor the views to the left and right?
FlowLayout class:
public class FlowLayout extends RelativeLayout {
private int mHorizontalSpacing;
private int mVerticalSpacing;
public FlowLayout(Context context) {
super(context);
}
public FlowLayout(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray attributes = context.obtainStyledAttributes(attrs, R.styleable.FlowLayout);
mHorizontalSpacing = attributes.getDimensionPixelSize(R.styleable
.FlowLayout_horizontalSpacing, 0);
mVerticalSpacing = attributes.getDimensionPixelSize(R.styleable
.FlowLayout_verticalSpacing, 0);
attributes.recycle();
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int width = 0;
int height = getPaddingTop();
int currentWidth = getPaddingStart();
int currentHeight = 0;
final int count = getChildCount();
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
LayoutParams lp = (LayoutParams) child.getLayoutParams();
measureChild(child, widthMeasureSpec, heightMeasureSpec);
if (currentWidth + child.getMeasuredWidth() > widthSize) {
height += currentHeight + mVerticalSpacing;
currentHeight = 0;
width = Math.max(width, currentWidth);
currentWidth = getPaddingEnd();
}
int spacing = mHorizontalSpacing;
if (lp.spacing > -1) {
spacing = lp.spacing;
}
lp.x = currentWidth + spacing;
lp.y = currentHeight;
currentWidth += child.getMeasuredWidth();
currentHeight = Math.max(currentHeight, child.getMeasuredHeight());
}
width += getPaddingEnd();
height += getPaddingBottom();
setMeasuredDimension(resolveSize(width, widthMeasureSpec), resolveSize(height,
heightMeasureSpec));
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
final int count = getChildCount();
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
LayoutParams lp = (LayoutParams) child.getLayoutParams();
child.layout(lp.x, lp.y, lp.x + child.getMeasuredWidth(), lp.y + child
.getMeasuredHeight());
}
}
#Override
protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
return p instanceof LayoutParams;
}
#Override
protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
return new LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout
.LayoutParams.WRAP_CONTENT);
}
#Override
protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
return new LayoutParams(p.width, p.height);
}
#Override
public RelativeLayout.LayoutParams generateLayoutParams(AttributeSet attrs) {
return new LayoutParams(getContext(), attrs);
}
public static class LayoutParams extends RelativeLayout.LayoutParams {
public int spacing;
public int x;
public int y;
public LayoutParams(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray attributes = context.obtainStyledAttributes(attrs, R.styleable
.FlowLayout_LayoutParams);
spacing = attributes.getDimensionPixelSize(R.styleable
.FlowLayout_LayoutParams_layoutSpacing, -1);
attributes.recycle();
}
public LayoutParams(int width, int height) {
super(width, height);
}
}
}
It turns out that rather than calculating the right view's new position yourself, you can change its LayoutParams and have the OS handle positioning for you. I created a custom layout that extends RelativeLayout and overrides the onMeasure() method. This will adjust the LayoutParams accordingly.
More specifically:
Call the super method then find the widths of the two views and their parent in onMeasure(). Use these to figure out if the right view will overlap the left view. If so, change the right view's layout_alignParentEnd="true" property to be layout_alignParentStart="true" and give it the layout_below="#id/left_view" property. Do the opposite when there will be no overlap. Call the super method again to have the OS remeasure the views for you.
The layout class:
public class WrappingLayout extends RelativeLayout {
private TextView leftView;
private EditText rightView;
//Use this to prevent unnecessarily adjusting the LayoutParams
//when the right view is already in the correct position
private boolean isMultiline = false;
public WrappingLayout(Context context) {
super(context);
LayoutInflater inflater = LayoutInflater.from(context);
inflater.inflate(R.layout.wrapping_layout, this);
leftView = (TextView) findViewById(R.id.left_view);
rightView = (EditText) findViewById(R.id.right_view);
}
public WrappingLayout(Context context, AttributeSet attrs) {
super(context, attrs);
LayoutInflater inflater = LayoutInflater.from(context);
inflater.inflate(R.layout.wrapping_layout, this);
leftView = (TextView) findViewById(R.id.left_view);
rightView = (EditText) findViewById(R.id.right_view);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//Call first to make sure the views' initial widths have been set
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int screenWidth = getMeasuredWidth();
int leftViewWidth = getPaddingStart() + leftView.getMeasuredWidth() + leftView.getPaddingEnd();
int rightViewWidth = getPaddingEnd() + rightView.getMeasuredWidth() + rightView.getPaddingStart();
LayoutParams rightViewParams = (LayoutParams) rightView.getLayoutParams();
if (!isMultiline && rightViewWidth + leftViewWidth > screenWidth) {
isMultiline = true;
rightViewParams.addRule(BELOW, R.id.left_view);
rightViewParams.removeRule(ALIGN_PARENT_END);
rightViewParams.addRule(ALIGN_PARENT_START);
//Call again here to adjust dimensions for new params
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
} else if (isMultiline && rightViewWidth + leftViewWidth < screenWidth) {
isMultiline = false;
rightViewParams.removeRule(BELOW);
rightViewParams.addRule(ALIGN_PARENT_END);
rightViewParams.removeRule(ALIGN_PARENT_START);
//Call again here to adjust dimensions for new params
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
}
The layout XML:
<?xml version="1.0" encoding="utf-8"?>
<merge
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">
<TextView
android:id="#id/left_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"/>
<EditText
android:id="#id/right_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:gravity="center"
android:text="#string/hello"/>
</merge>
I wrote a custom ViewGroup that organizes the subviews in matrix style (equally spaced vertically and horizontally). But I have a problem that is driving me crazy. The viewgroup draw correctly first levels child but them every subviews are invisible.
This is the code of layout
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:matrix="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<com.vincejin.timekiller.viewgroups.MatrixLayout
android:id="#+id/matrix"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#efefef"
matrix:ml_columns="2"
matrix:ml_horizontal_space="5dp"
matrix:ml_square="true"
matrix:ml_vertical_space="5dp" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#628465" >
<TextView
android:id="#+id/txv_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/text_default" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#763965" >
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#872438" >
</LinearLayout>
</com.vincejin.timekiller.viewgroups.MatrixLayout>
</LinearLayout>
The result is this
http://i40.tinypic.com/256tsw1.png
As you can see, the first layout has a textview inside but is not showed...
Here is the code of the viewgroup
Code:
package com.vincejin.timekiller.viewgroups;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import com.vincejin.timekiller.R;
public class MatrixLayout extends ViewGroup {
private boolean square;
private int columns ;
private int horizontalSpace ;
private int verticalSpace;
private int cellHeight;
private int cellWidth;
public MatrixLayout(Context context) {
super(context);
}
public MatrixLayout(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray arr = context.obtainStyledAttributes(attrs, R.styleable.MatrixLayout);
square = arr.getBoolean(R.styleable.MatrixLayout_ml_square,false);
columns = arr.getInteger(R.styleable.MatrixLayout_ml_columns, 4);
horizontalSpace = arr.getDimensionPixelSize(R.styleable.MatrixLayout_ml_horizontal_space, 3);
verticalSpace = arr.getDimensionPixelSize(R.styleable.MatrixLayout_ml_vertical_space, 3);
arr.recycle();
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
adjustChildren(l, t, r, b);
}
private void adjustChildren(int l, int t, int r, int b) {
int count = getChildCount();
int gone = 0;
for (int i = 0; i < count; i++) {
View currentChild = getChildAt(i);
if (currentChild.getVisibility() == View.GONE) {
gone++;
return;
}
Rect currentCellPosition = calculatePositionOf(l,t,r,b,coordinatesFromIndex(i
- gone));
currentChild.layout(
currentCellPosition.left,
currentCellPosition.top,
currentCellPosition.right,
currentCellPosition.bottom);
}
}
private Rect calculatePositionOf(int parentLeft, int parentTop, int parentRight, int parentBottom, int[] coordinates) {
int row = coordinates[0];
int col = coordinates[1];
Rect result = new Rect();
result.left = parentLeft + (col * (cellWidth + horizontalSpace));
result.right = result.left + cellWidth;
result.top = parentTop + (row * (cellHeight + verticalSpace));
result.bottom = result.top + cellHeight;
return result;
}
private int[] coordinatesFromIndex(int index) {
int[] result = new int[2];
result[0] = index / columns;
result[1] = index % columns;
return result;
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int w = MeasureSpec.getSize(widthMeasureSpec);
int h = MeasureSpec.getSize(heightMeasureSpec);
if (square) {
w = Math.min(w, h);
h = Math.min(w, h);
}
// Cell size calculus
int rows = getRowsCount();
cellWidth = (w / (columns)) ;
if(rows==0)
cellHeight = 0;
else
cellHeight = (h/ rows) ;
setMeasuredDimension(w, h);
}
private int getRowsCount() {
int childCount = getChildCount();
int gone = 0;
for (int i = 0; i < childCount; i++)
if (getChildAt(i).getVisibility() == View.GONE)
gone++;
if((childCount-gone)%columns==0)
return (childCount - gone) / columns;
return ((childCount - gone) / columns) + 1;
}
public boolean isSquare() {
return square;
}
public void setSquare(boolean square) {
this.square = square;
}
public int getColumns() {
return columns;
}
public void setColumns(int columns) {
this.columns = columns;
}
}
Here is the stylable
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="MatrixLayout">
<attr name="ml_columns" format="integer" />
<attr name="ml_square" format="boolean" />
<attr name="ml_vertical_space" format="dimension" />
<attr name="ml_horizontal_space" format="dimension" />
</declare-styleable>
</resources>
I solved with the help of pskink .
It was necessary to measure each child in the onMeasure method, so i added the follows rows at the end of the method.
cellWidthMeasure = MeasureSpec.makeMeasureSpec(cellWidth, MeasureSpec.EXACTLY);
cellHeightMeausure = MeasureSpec.makeMeasureSpec(cellHeight, MeasureSpec.EXACTLY);
int childCount = getChildCount();
for(int i=0;i<childCount;i++){
View child= getChildAt(i);
if(child.getVisibility()!=View.GONE)
child.measure(cellWidthMeasure,cellHeightMeausure);
}
I have a GridView that I have filled with 64 60x60px png's. I want the GridView to display them all as close to a perfect square as I can so I have set the numColumns in the XML to 8 so now I have an 8x8 gird.
Here is what it looks like:
My images actually have a small border at the very edge though that is being cropped off. Here I drew on the top left image what they should look like when displayed:
Here is my XML:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/textFieldFU"
android:layout_width="match_parent"
android:layout_height="match_parent"
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=".MainActivity" >
<GridView
android:id="#+id/gridview"
android:layout_width="fill_parent"
android:layout_height="600dp"
android:numColumns="8"
android:verticalSpacing="10dp"
android:horizontalSpacing="0dp"
android:stretchMode="columnWidth"
android:gravity="center"
/>
</RelativeLayout>
When I was using 40x40px and 50x50px size png's they worked fine, but they were too small to easily see my little symbols. I have changed everything in the XML that I could think of but no matter how much spacing I give or where I give it, the images stay cropped even when there is ample room.
How can I make the GridView display the full, un-cropped images?
For the love of all that is holy, I'm really dumb. I had forgotten that in my "ImageAdapter" class I had set had used the ImageView setLayoutParams method and set them to (50, 50). Sorry for wasting you good peoples time.
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ImageView iv;
if (convertView != null) {
iv = (ImageView) convertView;
} else {
iv = new ImageView(context);
******iv.setLayoutParams(new GridView.LayoutParams(50, 50));******
iv.setScaleType(ScaleType.CENTER);
iv.setPadding(0, 0, 0, 0);
}
iv.setImageResource(images[position]);
return iv;
}
To use flowlayout make a java class called FlowLayout to be a custom control in android.
.../src/FlowLayout.java:
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
public class FlowLayout extends ViewGroup
{
public static final int HORIZONTAL = 0;
public static final int VERTICAL = 1;
private int horizontalSpacing = 20;
private int verticalSpacing = 20;
private int orientation = 0;
private int innerPadding = 12;
public FlowLayout(Context context)
{
super(context);
}
public FlowLayout(Context context, AttributeSet attributeSet)
{
super(context, attributeSet);
}
public FlowLayout(Context context, AttributeSet attributeSet, int defStyle)
{
super(context, attributeSet, defStyle);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
int sizeWidth = MeasureSpec.getSize(widthMeasureSpec) - this.getPaddingRight() - this.getPaddingLeft();
int sizeHeight = MeasureSpec.getSize(heightMeasureSpec) - this.getPaddingRight() - this.getPaddingLeft()+innerPadding;
int modeWidth = MeasureSpec.getMode(widthMeasureSpec);
int modeHeight = MeasureSpec.getMode(heightMeasureSpec);
int size;
int mode;
if (orientation == HORIZONTAL)
{
size = sizeWidth;
mode = modeWidth;
}
else
{
size = sizeHeight;
mode = modeHeight;
}
int lineThicknessWithSpacing = 0;
int lineThickness = 0;
int lineLengthWithSpacing = 0;
int lineLength;
int prevLinePosition = 0;
int controlMaxLength = 0;
int controlMaxThickness = 0;
final int count = getChildCount();
for (int i = 0; i < count; i++)
{
final View child = getChildAt(i);
if (child.getVisibility() == GONE)
continue;
child.measure
(
MeasureSpec.makeMeasureSpec(sizeWidth, modeWidth == MeasureSpec.EXACTLY ? MeasureSpec.AT_MOST : modeWidth),
MeasureSpec.makeMeasureSpec(sizeHeight, modeHeight == MeasureSpec.EXACTLY ? MeasureSpec.AT_MOST : modeHeight)
);
LayoutParams lp = (LayoutParams) child.getLayoutParams();
int hSpacing = this.getHorizontalSpacing(lp);
int vSpacing = this.getVerticalSpacing(lp);
int childWidth = child.getMeasuredWidth();
int childHeight = child.getMeasuredHeight();
int childLength;
int childThickness;
int spacingLength;
int spacingThickness;
if (orientation == HORIZONTAL)
{
childLength = childWidth;
childThickness = childHeight;
spacingLength = hSpacing;
spacingThickness = vSpacing;
}
else
{
childLength = childHeight;
childThickness = childWidth;
spacingLength = vSpacing;
spacingThickness = hSpacing;
}
lineLength = lineLengthWithSpacing + childLength;
lineLengthWithSpacing = lineLength + spacingLength;
boolean newLine = lp.newLine || (mode != MeasureSpec.UNSPECIFIED && lineLength > size);
if (newLine)
{
prevLinePosition = prevLinePosition + lineThicknessWithSpacing;
lineThickness = childThickness;
lineLength = childLength;
lineThicknessWithSpacing = childThickness + spacingThickness;
lineLengthWithSpacing = lineLength + spacingLength;
}
lineThicknessWithSpacing = Math.max(lineThicknessWithSpacing, childThickness + spacingThickness);
lineThickness = Math.max(lineThickness, childThickness);
int posX;
int posY;
if (orientation == HORIZONTAL)
{
posX = innerPadding + getPaddingLeft() + lineLength - childLength;
posY = getPaddingTop() + prevLinePosition;
}
else
{
posX = getPaddingLeft() + prevLinePosition;
posY = innerPadding + getPaddingTop() + lineLength - childHeight;
}
lp.setPosition(posX, posY);
controlMaxLength = Math.max(controlMaxLength, lineLength);
controlMaxThickness = prevLinePosition + lineThickness;
}
if (orientation == HORIZONTAL)
this.setMeasuredDimension(resolveSize(controlMaxLength, widthMeasureSpec), resolveSize(controlMaxThickness, heightMeasureSpec));
else
this.setMeasuredDimension(resolveSize(controlMaxThickness, widthMeasureSpec), resolveSize(controlMaxLength, heightMeasureSpec));
}
private int getVerticalSpacing(LayoutParams lp)
{
int vSpacing;
if (lp.verticalSpacingSpecified())
vSpacing = lp.verticalSpacing;
else
vSpacing = this.verticalSpacing;
return vSpacing;
}
private int getHorizontalSpacing(LayoutParams lp)
{
int hSpacing;
if (lp.horizontalSpacingSpecified())
hSpacing = lp.horizontalSpacing;
else
hSpacing = this.horizontalSpacing;
return hSpacing;
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b)
{
final int count = getChildCount();
for (int i = 0; i < count; i++)
{
View child = getChildAt(i);
LayoutParams lp = (LayoutParams) child.getLayoutParams();
child.layout(lp.x, lp.y, lp.x + child.getMeasuredWidth(), lp.y + child.getMeasuredHeight());
}
}
#Override
protected boolean drawChild(Canvas canvas, View child, long drawingTime)
{
return super.drawChild(canvas, child, drawingTime);
}
#Override
protected boolean checkLayoutParams(ViewGroup.LayoutParams p)
{
return p instanceof LayoutParams;
}
#Override
protected LayoutParams generateDefaultLayoutParams()
{
return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
}
#Override
public LayoutParams generateLayoutParams(AttributeSet attributeSet)
{
return new LayoutParams(getContext(), attributeSet);
}
#Override
protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p)
{
return new LayoutParams(p);
}
public static class LayoutParams extends ViewGroup.LayoutParams
{
private static int NO_SPACING = -1;
private int x;
private int y;
private int horizontalSpacing = NO_SPACING;
private int verticalSpacing = NO_SPACING;
private boolean newLine = false;
public LayoutParams(Context context, AttributeSet attributeSet)
{
super(context, attributeSet);
this.readStyleParameters(context, attributeSet);
}
public LayoutParams(int width, int height)
{
super(width, height);
}
public LayoutParams(ViewGroup.LayoutParams layoutParams)
{
super(layoutParams);
}
public boolean horizontalSpacingSpecified()
{
return horizontalSpacing != NO_SPACING;
}
public boolean verticalSpacingSpecified()
{
return verticalSpacing != NO_SPACING;
}
public void setPosition(int x, int y)
{
this.x = x;
this.y = y;
}
private void readStyleParameters(Context context, AttributeSet attributeSet)
{
TypedArray a = context.obtainStyledAttributes(attributeSet, R.styleable.FlowLayout_LayoutParams);
try
{
horizontalSpacing = a.getDimensionPixelSize(R.styleable.FlowLayout_LayoutParams_layout_horizontalSpacing, NO_SPACING);
verticalSpacing = a.getDimensionPixelSize(R.styleable.FlowLayout_LayoutParams_layout_verticalSpacing, NO_SPACING);
newLine = a.getBoolean(R.styleable.FlowLayout_LayoutParams_layout_newLine, false);
}
finally
{
a.recycle();
}
}
}
}
Then you create custom attributes for your views that are going to be inside the flow layout view.
.../res/values/attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="FlowLayout_LayoutParams">
<attr name="layout_newLine" format="boolean"/>
<attr name="layout_horizontalSpacing" format="dimension"/>
<attr name="layout_verticalSpacing" format="dimension"/>
</declare-styleable>
</resources>
Then in the xml layout you just add:
<[PATH_TO_CLASS].FlowLayout
xmlns:flowLayout="http://schemas.android.com/apk/res/za.co.lawdata.searchworks"
android:id="#+id/flow_layout"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button"
flowLayout:layout_verticalSpacing="50dp"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button"
flowLayout:layout_newLine="true"
flowLayout:layout_horizontalSpacing="50dp"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button"/>
</[PATH_TO_CLASS].FlowLayout>
And replace [PATH_TO_CLASS] with your package path eg: com.example.appname
flowLayout:layout_verticalSpacing="50dp" will set the vertical space between the item.
The default is set in the java class.
flowLayout:layout_horizontalSpacing="50dp" will set the horizontal space between the item.
The default is set in the java class.
flowLayout:layout_newLine="true" will put the item on a new line.
This is an edit from this git: https://github.com/ApmeM/android-flowlayout
Please help! I tried everything! :(
I've got a schedule Class, which is simply a custom ViewGroup (with custom onMeasure() and onLayout()), which enables me to place childs(=events) with LayoutParams for column/row start and column/row end. The number of childs and their LayoutParams depend on database entries.
Now I'm trying to add childs (events) from my database. I'd have to use a Cursor Adapter, so my schedule Class has to extend ListView, right? I tried that but the newView() method of the adapter is never called. Why not??
My custom ListView doesn't ask the adapter for childs, no childs are added. I also can't add the childs by hand calling schedule.addView() if I extend from AdapterView.
I'd be really (really) happy if someone could help!
Regards,
cody
This is my custom ViewGroup:
public class Schedule extends ViewGroup {
private int columns;
private int rows;
private float preferredCellWidth;
private float preferredCellHeight;
private String[] rowTimes;
private Paint paint;
public Schedule(Context context, int columns, int rows, float preferredCellWidth, float preferredCellHeight, String[] rowTimes) {
super(context);
this.columns = columns;
this.rows = rows;
this.preferredCellWidth = preferredCellWidth;
this.preferredCellHeight = preferredCellHeight;
this.rowTimes = rowTimes;
init(context);
}
private void init(Context context) {
Log.i("Schedule", "initSchedule...");
setPaint();
setWillNotDraw(false);
}
private void setPaint() {
paint = new Paint();
paint.setTextSize(preferredCellHeight*2/3);
paint.setStyle(Paint.Style.STROKE);
paint.setColor(getResources().getColor(R.color.white));
}
public Schedule(Context context, AttributeSet attrs) {
super(context, attrs);
readAttr(context, attrs);
init(context);
}
public Schedule(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
readAttr(context, attrs);
init(context);
}
private void readAttr(Context c, AttributeSet attrs) {
android.content.res.TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.ScheduleLayout);
this.columns = a.getInt(R.styleable.ScheduleLayout_columns, 1);
this.rows = a.getInt(R.styleable.ScheduleLayout_rows, 1);
this.preferredCellWidth = a.getDimension(R.styleable.ScheduleLayout_preferredCellWidth, 1);
this.preferredCellHeight = a.getDimension(R.styleable.ScheduleLayout_preferredCellHeight, 1);
a.recycle();
}
#Override
protected void onDraw(Canvas canvas) {
//Log.i(this.toString(),"onDraw ..."+" this.getLeft()="+this.getLeft()+", this.getWidth()="+this.getWidth());
super.onDraw(canvas);
for (int i = 0; i < rows; i++) {
int line = (int) Math.round(this.getTop()+ (i+1) * preferredCellHeight);
canvas.drawText(this.rowtimes[i], this.getLeft()+5, line-3, paint);
canvas.drawLine(this.getLeft(), line, this.getWidth(), line, paint);
}
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Log.i("Schedule", "onMeasure...");
float width = (MeasureSpec.getSize(widthMeasureSpec) - getPaddingLeft() - getPaddingRight()) / columns;
float height = (MeasureSpec.getSize(heightMeasureSpec) - getPaddingTop() - getPaddingBottom()) / rows;
float cellWidth = preferredCellWidth;
float cellHeight = preferredCellHeight;
if (MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY) {
cellWidth = width;
} else if (MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.AT_MOST) {
cellWidth = Math.min(preferredCellWidth, width);
}
if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY) {
cellHeight = height;
} else if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST) {
cellHeight = Math.min(preferredCellHeight, height);
}
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
if (child.getVisibility() != GONE) {
LayoutParams lp = (LayoutParams) child.getLayoutParams();
int cwidth = (int) Math.round(cellWidth * lp.getWidth());
int cheight = (int) Math.round(cellHeight * lp.getHeight());
child.measure(
MeasureSpec.makeMeasureSpec(cwidth, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(cheight, MeasureSpec.EXACTLY)
);
}
}
setMeasuredDimension(
(int) Math.round(cellWidth * columns + getPaddingLeft() + getPaddingRight()),
(int) Math.round(cellHeight * rows + getPaddingTop() + getPaddingBottom())
);
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
if (!changed)
return;
int cellWidth = ((r-l) - getPaddingLeft() - getPaddingRight()) / columns;
int cellHeight = ((b-t) - getPaddingTop() - getPaddingBottom()) / rows;
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
if (child.getVisibility() != GONE) {
LayoutParams lp = (LayoutParams) child.getLayoutParams();
int cl = (int) Math.round(getPaddingLeft() + lp.columnStart * cellWidth);
int cr = (int) Math.round(getPaddingLeft() + lp.columnEnd * cellWidth);
int ct = (int) Math.round(getPaddingTop() + lp.rowStart * cellHeight);
int cb = (int) Math.round(getPaddingTop() + lp.rowEnd * cellHeight);
child.layout(cl, ct, cr, cb);
}
}
}
protected boolean checkLayoutParams(android.view.ViewGroup.LayoutParams p) {
Log.i("Schedule", "checkLayoutParams...");
if (p instanceof LayoutParams) {
LayoutParams lp = (LayoutParams) p;
if (lp.columnEnd > columns || lp.columnStart < 0)
return false;
if (lp.rowEnd > rows || lp.rowStart < 0)
return false;
return lp.columnEnd > lp.columnStart && lp.rowEnd > lp.rowStart;
} else
return false;
}
public android.widget.AbsListView.LayoutParams generateLayoutParams(AttributeSet attrs) {
return new android.widget.AbsListView.LayoutParams(getContext(), attrs);
}
public static class LayoutParams extends android.view.ViewGroup.LayoutParams {
public int columnStart;
public int columnEnd;
public int rowStart;
public int rowEnd;
public LayoutParams(int columnStart, int rowStart, int columnEnd, int rowEnd) {
super(WRAP_CONTENT, WRAP_CONTENT);
this.columnStart = columnStart;
this.columnEnd = columnEnd;
this.rowStart = rowStart;
this.rowEnd = rowEnd;
}
public LayoutParams(Context c, AttributeSet attrs) {
super(WRAP_CONTENT, WRAP_CONTENT);
android.content.res.TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.EventLayout);
this.columnStart = a.getInt(R.styleable.EventLayout_event_columnStart, 0);
this.columnEnd = a.getInt(R.styleable.EventLayout_event_columnEnd, this.columnStart + 1);
this.rowStart = a.getInt(R.styleable.EventLayout_event_rowStart, 0);
this.rowEnd = a.getInt(R.styleable.EventLayout_event_rowEnd, this.rowStart + 1);
a.recycle();
}
public int getWidth() {
return columnEnd - columnStart;
}
public int getHeight() {
return rowEnd - rowStart;
}
}
And this is the event-layout - event.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:orientation="vertical"
android:gravity="center" >
<TextView android:id="#+id/text_event_name"
style="#style/Event_TextView1" />
<TextView android:id="#+id/text_event_name2"
style="#style/Event_TextView2" />
</LinearLayout>
<TextView android:id="#+id/text_event_weeks"
style="#style/Event_TextView2"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true" />
<TextView android:id="#+id/text_event_room"
style="#style/Event_TextView2"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true" />
In my Activity I've got that code:
Schedule schedule = new Schedule(this, 4, rowTimes.length, 15, 15, rowTimes);
Cursor cursor = dbManager.getEvents(day);
MySimpleCurserAdapter adapter = ... ??
// schedule.setAdapter not working...
How can I add events to the schedule with the data from the cursor?
You should not need to be extending ListView. You just want to add an instance of ListView to your layout.
It sounds like you might want to be using a SimpleCursorAdaptor, where you can map items in your custom view to the data model objects you want them to display.
See Binding to Data with Adapter and Hello ListView for some examples of the right ways to use adapters and ListViews.