Вот реализация класса SimpleListView
. Я знаю, что это неэффективно, и я почти уверен, что содержит ошибки, но показывает, как измерить ширину представления списка.
Я также рекомендую прочитать эту статью .
public class SimpleListView extends AdapterView<ListAdapter> {
private ListAdapter adapter;
private Drawable divider;
private int dividerHeight;
private boolean clipDivider;
public SimpleListView( final Context context )
{
this( context, null );
}
public SimpleListView( final Context context, final AttributeSet attrs )
{
this( context, attrs, android.R.attr.listViewStyle );
}
public SimpleListView( final Context context, final AttributeSet attrs, final int defStyle )
{
super( context, attrs, defStyle );
final TypedArray array =
context.obtainStyledAttributes( attrs, R.styleable.SimpleListView, defStyle, 0 );
final Drawable dividerAttribute =
array.getDrawable( R.styleable.SimpleListView_android_divider );
if( dividerAttribute != null ) {
setDivider( dividerAttribute );
}
final int dividerHeightAttribute =
array.getDimensionPixelSize( R.styleable.SimpleListView_android_dividerHeight, 0 );
if( dividerHeightAttribute != 0 ) {
setDividerHeight( dividerHeightAttribute );
}
array.recycle();
}
public Drawable getDivider()
{
return this.divider;
}
public void setDivider( final Drawable newDivider )
{
if( newDivider != null ) {
this.dividerHeight = newDivider.getIntrinsicHeight();
this.clipDivider = newDivider instanceof ColorDrawable;
} else {
this.dividerHeight = 0;
this.clipDivider = false;
}
this.divider = newDivider;
requestLayout();
}
public int getDividerHeight()
{
return this.dividerHeight;
}
public void setDividerHeight( final int newHeight )
{
this.dividerHeight = newHeight;
requestLayout();
}
@Override
public ListAdapter getAdapter()
{
return this.adapter;
}
@Override
public void setAdapter( final ListAdapter adapter )
{
this.adapter = adapter;
removeAllViewsInLayout();
requestLayout();
}
@Override
public View getSelectedView()
{
throw new UnsupportedOperationException(
"SimpleListView.getSelectedView() is not supported" );
}
@Override
public void setSelection( final int position )
{
throw new UnsupportedOperationException(
"SimpleListView.setSelection(int) is not supported" );
}
@Override
protected void onMeasure( final int widthMeasureSpec, final int heightMeasureSpec )
{
super.onMeasure( widthMeasureSpec, heightMeasureSpec );
final int widthMode = MeasureSpec.getMode( widthMeasureSpec );
int widthSize = MeasureSpec.getSize( widthMeasureSpec );
final int heightMode = MeasureSpec.getMode( heightMeasureSpec );
int heightSize = MeasureSpec.getSize( heightMeasureSpec );
int innerWidth = 0;
int innerHeight = 0;
final int itemCount = this.adapter == null ? 0 : this.adapter.getCount();
if( itemCount > 0
&& ( widthMode != MeasureSpec.EXACTLY || heightMode != MeasureSpec.EXACTLY ) ) {
for( int i = 0; i < itemCount; ++i ) {
final View convertView = getChildAt( i );
final View child = this.adapter.getView( i, convertView, this );
if( convertView == null ) {
LayoutParams params = child.getLayoutParams();
if( params == null ) {
params = new LayoutParams( LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT );
child.setLayoutParams( params );
}
addViewInLayout( child, i, params );
}
if( child.getLayoutParams() instanceof MarginLayoutParams ) {
measureChildWithMargins( child, widthMeasureSpec, 0, heightMeasureSpec, 0 );
} else {
measureChild( child, widthMeasureSpec, heightMeasureSpec );
}
innerWidth = Math.max( innerWidth, child.getMeasuredWidth() );
innerHeight += child.getMeasuredHeight();
}
innerHeight += ( itemCount - 1 ) * this.dividerHeight;
}
if( widthMode != MeasureSpec.EXACTLY ) {
final int newWidthSize = getPaddingLeft() + getPaddingRight() + innerWidth;
widthSize =
widthMode == MeasureSpec.AT_MOST ? Math.min( widthSize, newWidthSize )
: newWidthSize;
}
if( heightMode != MeasureSpec.EXACTLY ) {
final int newHeightSize = getPaddingTop() + getPaddingBottom() + innerHeight;
heightSize =
heightMode == MeasureSpec.AT_MOST ? Math.min( heightSize, newHeightSize )
: newHeightSize;
}
setMeasuredDimension( widthSize, heightSize );
}
@Override
protected void onLayout( final boolean changed, final int left, final int top, final int right,
final int bottom )
{
super.onLayout( changed, left, top, right, bottom );
if( this.adapter == null ) {
return;
}
positionItems();
invalidate();
}
private void positionItems()
{
int top = getPaddingTop();
final int left = getPaddingLeft();
for( int i = 0, count = getChildCount(); i < count; ++i ) {
final View child = getChildAt( i );
final int width = child.getMeasuredWidth();
final int height = child.getMeasuredHeight();
child.layout( left, top, left + width, top + height );
top += height + this.dividerHeight;
}
}
@Override
protected void dispatchDraw( final Canvas canvas )
{
final boolean drawDividers = this.dividerHeight > 0 && this.divider != null;
if( drawDividers ) {
final int left = getPaddingLeft();
final int right = getWidth() - getPaddingRight();
final Rect dividerBounds = new Rect( left, 0, right, 0 );
for( int i = 0, count = getChildCount(); i < count - 1; ++i ) {
final View child = getChildAt( i );
dividerBounds.top = dividerBounds.bottom + child.getMeasuredHeight();
dividerBounds.bottom = dividerBounds.top + this.dividerHeight;
drawDivider( canvas, dividerBounds );
}
}
super.dispatchDraw( canvas );
}
private void drawDivider( final Canvas canvas, final Rect bounds )
{
if( !this.clipDivider ) {
this.divider.setBounds( bounds );
} else {
canvas.save();
canvas.clipRect( bounds );
}
this.divider.draw( canvas );
if( this.clipDivider ) {
canvas.restore();
}
}
}