I use a RecyclerView with some dividers between items. I use a DividerDecorator to draw them. But on older android versions (API 8) it draws the complete background in my divider color. Here is my code:
public class DividerItemDecoration extends RecyclerView.ItemDecoration {
public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL;
public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL;
private final Drawable mDivider;
private final int mHeight;
private int mOrientation;
public DividerItemDecoration( final Context context, final int orientation) {
mDivider = new ColorDrawable( context.getResources().getColor( R.color.divider) );
mHeight = dpToPx( 1f, context.getResources() );
setOrientation(orientation);
}
private int dpToPx( final float dp, final Resources resource ) {
float px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, resource.getDisplayMetrics() );
return Math.max( 1, (int) px );
}
public void setOrientation( final int orientation) {
if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) {
throw new IllegalArgumentException("invalid orientation");
}
mOrientation = orientation;
}
#Override
public void onDraw( final Canvas c, final RecyclerView parent, final RecyclerView.State state) {
if( mOrientation == VERTICAL_LIST ) {
drawVertical(c, parent);
} else {
drawHorizontal(c, parent);
}
}
public void drawVertical( final Canvas c, final RecyclerView parent ) {
final int left = parent.getPaddingLeft();
final int right = parent.getWidth() - parent.getPaddingRight();
final int childCount = parent.getChildCount();
View child;
RecyclerView.LayoutParams params;
int top;
int bottom;
for( int position = 0; position < childCount; position++) {
child = parent.getChildAt(position);
params = (RecyclerView.LayoutParams) child.getLayoutParams();
top = child.getBottom() + params.bottomMargin;
bottom = top + mHeight;
mDivider.setBounds( left, top, right, bottom );
mDivider.draw(c);
}
}
public void drawHorizontal( final Canvas c, final RecyclerView parent ) {
final int top = parent.getPaddingTop();
final int bottom = parent.getHeight() - parent.getPaddingBottom();
final int childCount = parent.getChildCount();
View child;
RecyclerView.LayoutParams params;
int left;
int right;
for( int position = 0; position < childCount; position++) {
child = parent.getChildAt( position );
params = (RecyclerView.LayoutParams) child.getLayoutParams();
left = child.getRight() + params.rightMargin;
right = left + mHeight;
mDivider.setBounds( left, top, right, bottom );
mDivider.draw( c );
}
}
#Override
public void getItemOffsets( final Rect outRect, final View view, final RecyclerView parent, final RecyclerView.State state) {
if (mOrientation == VERTICAL_LIST) {
outRect.set( 0 /*left*/, 0 /*top*/, 0 /*right*/, mHeight /*bottom*/ );
} else {
outRect.set( 0 /*left*/, 0 /*top*/, mHeight /*right*/, 0 /*bottom*/ );
}
}
}
Here is my log from divider coordinates and they look correct:
DividerItemDecoration﹕ divider=0, left=0, top=66, right=240, bottom=67
DividerItemDecoration﹕ divider=1, left=0, top=133, right=240, bottom=134
DividerItemDecoration﹕ divider=2, left=0, top=200, right=240, bottom=201
DividerItemDecoration﹕ divider=3, left=0, top=267, right=240, bottom=268
Related
I have RecyclerView item decoration and add my RecyclerView. RecyclerView divider lost when change item background color.
My RecyclerView with divider:
When RecyclerView items selected, not show divider:
setBackgroundColor:
private void setBackgroundColor() {
if (selectedItem.isEmpty() || !selectedItem.contains(item)) {
this.setBackgroundColor(Color.TRANSPARENT);
} else {
this.setBackgroundColor(0xffffedc7);
}
}
DividerItemDecoration:
public class DividerItemDecoration extends RecyclerView.ItemDecoration {
private Drawable mDivider;
public DividerItemDecoration(int resId) {
mDivider = ContextCompat.getDrawable(MyApplication.getContext(), resId);
}
#Override
public void onDraw(#NonNull Canvas canvas, RecyclerView parent, #NonNull RecyclerView.State state) {
int left = MyApplication.getContext().getResources().getDimensionPixelSize(R.dimen.profileImageSizeDivider);
int right = parent.getWidth() - parent.getPaddingRight();
int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
View child = parent.getChildAt(i);
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
int top = child.getBottom() + params.bottomMargin;
int bottom = top + mDivider.getIntrinsicHeight();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(canvas);
}
}
}
Try this:
/**
* Draws left or right inset dividers at the bottom of every recycler item view. Only supports
* vertical orientations.
*/
public class InsetDividerItemDecoration extends RecyclerView.ItemDecoration {
private int mLeftInset = 0;
private int mRightInset = 0;
private int mStartPosition = 0;
final private Paint mLinePaint = new Paint();
final private List<Integer> mPositionsToIgnore = new ArrayList<>();
public InsetDividerItemDecoration(int leftInset, int rightInset, int dividerColor) {
mLeftInset = leftInset;
mRightInset = rightInset;
setColor(dividerColor);
}
public InsetDividerItemDecoration(int leftInset, int rightInset, int dividerColor, int startPosition) {
mLeftInset = leftInset;
mRightInset = rightInset;
mStartPosition = startPosition;
setColor(dividerColor);
}
public InsetDividerItemDecoration(int leftInset, int rightInset, int dividerColor, int startPosition, int dividerHeight) {
mLeftInset = leftInset;
mRightInset = rightInset;
mStartPosition = startPosition;
setColor(dividerColor);
setDividerHeight(dividerHeight);
}
public InsetDividerItemDecoration(int leftInset, int rightInset) {
this(leftInset, rightInset, 0);
}
public int getColor() {
return mLinePaint.getColor();
}
public void setColor(int color) {
mLinePaint.setColor(color);
}
public int getLeftInset() {
return mLeftInset;
}
public void setLeftInset(int leftInset) {
mLeftInset = leftInset;
}
public int getRightInset() {
return mRightInset;
}
public void setRightInset(int rightInset) {
mRightInset = rightInset;
}
public void setDividerHeight(int height) {
mLinePaint.setStrokeWidth(height);
}
public int getDividerHeight() {
return (int) mLinePaint.getStrokeWidth();
}
#Override
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
final int visibleItems = parent.getLayoutManager().getChildCount();
for (int i = 0; i < visibleItems; i++) {
View itemView = parent.getLayoutManager().getChildAt(i);
final int adapterPosition = parent.getChildAdapterPosition(itemView);
final boolean shouldDraw = adapterPosition != RecyclerView.NO_POSITION
&& adapterPosition != parent.getAdapter().getItemCount() - 1
&& adapterPosition >= mStartPosition
&& !shouldIgnoreAdapterPosition(adapterPosition);
if (shouldDraw) {
Rect itemRect = new Rect();
itemView.getDrawingRect(itemRect);
parent.offsetDescendantRectToMyCoords(itemView, itemRect);
final int lineStartX = mLeftInset;
final int lineStartY = itemRect.bottom;
final int lineEndX = itemRect.right - mRightInset;
final int lineEndY = lineStartY;
c.drawLine(lineStartX, lineStartY, lineEndX, lineEndY, mLinePaint);
}
}
}
protected boolean shouldIgnoreAdapterPosition(int position) {
return mPositionsToIgnore.size() > 0 && mPositionsToIgnore.contains(position);
}
public void setStartPosition(int startPosition) {
mStartPosition = startPosition;
}
public void setPositionsToIgnore(List<Integer> positionsToIgnore) {
mPositionsToIgnore.clear();
if (positionsToIgnore != null) {
mPositionsToIgnore.addAll(positionsToIgnore);
}
}
public void setPositionsToIgnore(Integer[] positionsToIgnore) {
setPositionsToIgnore(Arrays.asList(positionsToIgnore));
}
}
I currently have this Recyclerview with a solid line ItemDecoration separating the elements.:
but want to have a RecyclerView ItemDecoration with a style like this one:
This is my decoration with just solid vertical and horizontal lines without line spaces like my example :
public class GridDividerDecoration extends RecyclerView.ItemDecoration {
private static final int[] ATTRS = {android.R.attr.listDivider};
private Drawable mDivider;
private int mInsets;
public GridDividerDecoration(Context context) {
TypedArray a = context.obtainStyledAttributes(ATTRS);
mDivider = a.getDrawable(0);
a.recycle();
mInsets = context.getResources().getDimensionPixelSize(R.dimen.card_insets);
}
#Override
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
drawVertical(c, parent);
drawHorizontal(c, parent);
}
public void drawVertical(Canvas c, RecyclerView parent) {
if (parent.getChildCount() == 0) return;
final int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = parent.getChildAt(i);
final RecyclerView.LayoutParams params =
(RecyclerView.LayoutParams) child.getLayoutParams();
final int left = child.getLeft() - params.leftMargin - mInsets;
final int right = child.getRight() + params.rightMargin + mInsets;
final int top = child.getBottom() + params.bottomMargin + mInsets;
final int bottom = top + mDivider.getIntrinsicHeight();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
public void drawHorizontal(Canvas c, RecyclerView parent) {
final int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = parent.getChildAt(i);
final RecyclerView.LayoutParams params =
(RecyclerView.LayoutParams) child.getLayoutParams();
final int left = child.getRight() + params.rightMargin + mInsets;
final int right = left + mDivider.getIntrinsicWidth();
final int top = child.getTop() - params.topMargin - mInsets;
final int bottom = child.getBottom() + params.bottomMargin + mInsets;
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
#Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
outRect.set(mInsets, mInsets, mInsets, mInsets);
}
}
anyone can help how to set some spaces between lines ?
You just want to have slightly shorter lines so just amend your bounds.
e.g:
For the vertical line, you have:
mDivider.setBounds(left, top, right, bottom);
so just change the top and bottom offsets like this:
mDivider.setBounds(left, top + 10, right, bottom - 10);
Do a similar thing for the horizontal lines but change the left and right offsets.
You can experiment with the actual values until you get the effect you want.
I have just started using ItemDecoration. I am trying to achieve a divider in the middle of a two-column RecyclerView managed by StaggeredGridLayoutManager.
Here's my ItemDecoration code :
public class LobbyItemDecoration extends RecyclerView.ItemDecoration {
private int margin;
private Drawable drawable;
public LobbyItemDecoration(int margin, Drawable drawable){
this.margin = margin;
this.drawable = drawable;
}
#Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
int position = parent.getChildAdapterPosition(view);
StaggeredGridLayoutManager.LayoutParams lp = (StaggeredGridLayoutManager.LayoutParams)view .getLayoutParams();
int spanIndex = lp.getSpanIndex();
if(position >= 0){
if (position < ((LobiAdapter)parent.getAdapter()).getmDataset().size()){
if(spanIndex == 1){
outRect.left = margin;
((LobiAdapter)parent.getAdapter()).getmDataset().get(position).left = false;
} else {
outRect.right = margin;
((LobiAdapter)parent.getAdapter()).getmDataset().get(position).left = true;
}
outRect.bottom = margin;
}
}
}
#Override
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
if (drawable == null) { super.onDrawOver(c, parent, state);return; }
if(parent.getItemAnimator() != null && parent.getItemAnimator().isRunning()) {
return;
}
final int top = parent.getPaddingTop();
final int bottom = parent.getHeight() - parent.getPaddingBottom();
final int childCount = parent.getChildCount();
for (int i=1; i < childCount; i++) {
final View child = parent.getChildAt(i);
StaggeredGridLayoutManager.LayoutParams lp = (StaggeredGridLayoutManager.LayoutParams)child .getLayoutParams();
int spanIndex = lp.getSpanIndex();
int size = drawable.getIntrinsicWidth();
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
final int ty = (int)(child.getTranslationY() + 0.5f);
final int tx = (int)(child.getTranslationX() + 0.5f);
final int leftIndex1 = child.getLeft() - (margin * 4 / 3) - tx;
final int rightIndex1 = child.getLeft() - (margin * 2 / 3) - tx;
final int leftIndex0 = child.getRight() + (margin * 2 / 3) + tx;
final int rightIndex0 = child.getRight() + (margin * 4 / 3) + tx;
if(spanIndex == 1){
// drawable.setBounds(100, top, 5, bottom);
drawable.setBounds(leftIndex1, top, rightIndex1, bottom);
drawable.draw(c);
} else {
drawable.setBounds(leftIndex0, top, rightIndex0, bottom);
drawable.draw(c);
// drawable.setBounds(5, top, 100, bottom);
}
}
}
}
Problem is as title said, whenever I load new item or scroll, the decoration is sometimes gone or misplaced. By gone I mean, literally gone, it's not there anymore until I scroll down or up to recycle the View.
And by misplaced I mean, when I scroll down, and the loading ViewHolder is in the left column, the divider "sticks" to the left column. If the loading ViewHolder is in the right column, it is normal.
Just in case : I use a ViewHolder to be a progress indicator by adding one null item and check it in getItemViewType() then remove it later after finishing the load from server.
This is how I add :
for (PostModel postModel :
dataSet) {
this.mDataset.add(postModel);
notifyItemInserted(mDataset.size() - 1);
}
StaggeredGridLayoutManager is buggy. For me this helped:
diffResult.dispatchUpdatesTo(this);
recyclerView.postDelayed(() -> {
layoutManager.invalidateSpanAssignments(); // to fix first item in second column issue
recyclerView.invalidateItemDecorations(); // to fix wrong spacing
}, 50);
Is there any way to removing divider after a footer in a Recyclerview.I am using item decoration to add divider to the adapter.I am adding footer in the adapter.divider is showing below the footer also.i want to remove it.
This is my code for Divider
public class DividerItemDecoration extends RecyclerView.ItemDecoration {
private static final int[] ATTRS = new int[]{
android.R.attr.listDivider
};
public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL;
public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL;
private Drawable mDivider;
private int mOrientation;
public DividerItemDecoration(Context context, int orientation) {
final TypedArray a = context.obtainStyledAttributes(ATTRS);
mDivider = a.getDrawable(0);
a.recycle();
setOrientation(orientation);
}
public void setOrientation(int orientation) {
if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) {
throw new IllegalArgumentException("invalid orientation");
}
mOrientation = orientation;
}
#Override
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
if (mOrientation == VERTICAL_LIST) {
drawVertical(c, parent);
} else {
drawHorizontal(c, parent);
}
}
public void drawVertical(Canvas c, RecyclerView parent) {
final int left = parent.getPaddingLeft();
final int right = parent.getWidth() - parent.getPaddingRight();
final int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = parent.getChildAt(i);
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
.getLayoutParams();
final int top = child.getBottom() + params.bottomMargin;
final int bottom = top + mDivider.getIntrinsicHeight();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
public void drawHorizontal(Canvas c, RecyclerView parent) {
final int top = parent.getPaddingTop();
final int bottom = parent.getHeight() - parent.getPaddingBottom();
final int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = parent.getChildAt(i);
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
.getLayoutParams();
final int left = child.getRight() + params.rightMargin;
final int right = left + mDivider.getIntrinsicHeight();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
#Override
public void getItemOffsets(Rect rect, View view, RecyclerView parent, RecyclerView.State state) {
if (Orientation == VERTICAL_LIST) {
rect.set(0, 0, 0, Divider.getIntrinsicHeight());
} else {
rect.set(0, 0, Divider.getIntrinsicWidth(), 0);
}}
You have to add a check on getItemOffsets() method:
#Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
if (parent.getChildAdapterPosition(view) != parent.getAdapter().getItemCount() - 1) {
// set the rect's size
}
}
You can find an example of this implementation on my RecyclerViewDivider library on Github
Or you can simply add it as a Gradle dependency and check the javadoc:
dependencies {
...
compile 'com.github.fondesa:recycler-view-divider:1.1.3'
}
And use:
RecyclerViewDivider.with(context)
.addTo(recyclerView)
.visibilityFactory(new VisibilityFactory() {
#Override
public boolean displayDividerForItem(int listSize, int position) {
return position != listSize - 1;
}
})
.build()
.attach()
I inflated a ListView as the contentView in a PopupWindow.
If I don't set the width & height, I can't see the PopupWindow.
If I set them like this:
setWindowLayoutMode(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
The layout is being set like "fill_parent". Why?
The layout attributes of the ListView and ListView item are all set to "wrap_content".
Any suggestion? Thanks.
This is how to do it:
// Don't use this. It causes ListView's to have strange widths, similar to "fill_parent"
//popupWindow.setWindowLayoutMode(WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT);
// Instead, use this:
final int NUM_OF_VISIBLE_LIST_ROWS = 4;
listView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
popupWindow.setWidth(listView.getMeasuredWidth());
popupWindow.setHeight((listView.getMeasuredHeight() + 10) * NUM_OF_VISIBLE_LIST_ROWS);
Note that setWidth() and setHeight() use raw pixel values, so you need to adjust for different screen sizes and different densities.
My solution is override onMeasure of ListView like this:
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int maxWidth = meathureWidthByChilds() + getPaddingLeft() + getPaddingRight();
super.onMeasure(MeasureSpec.makeMeasureSpec(maxWidth, MeasureSpec.EXACTLY), heightMeasureSpec);
}
public int meathureWidthByChilds() {
int maxWidth = 0;
View view = null;
for (int i = 0; i < getAdapter().getCount(); i++) {
view = getAdapter().getView(i, view, this);
view.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
if (view.getMeasuredWidth() > maxWidth){
maxWidth = view.getMeasuredWidth();
}
}
return maxWidth;
}
Here's the SimpleListView class implementation. I know it's inefficient and I'm pretty sure it contains errors, but it shows how to measure a width of a list view.
I also recommend to read this article.
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();
}
}
}
I faced the same problem. The only solution I found is to set the PopupWindow width to the exact width of the ListView:
listView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
final PopupWindow popup = new PopupWindow(listView, listView.getMeasuredWidth(),
ViewGroup.LayoutParams.WRAP_CONTENT, true);
popup.showAsDropDown(anchor);
Unfortunately, it doesn't solve the problem entirely. The ListView measures itself so that it can wrap only its first child. If for example the second child is wider than the first one, the second child will be clipped.
I'm not sure, but the only way to change the way the ListView measures itself is to subclass it and override the onMeasure() method. I'm trying to do it now and I'll write a comment here if I succeed in it.