How to add dividers to LinearLayoutICS?
W

1

0

Background

I'm trying to switch my alternative "App Manager" app from ActionBarSherlock library to the support library Google has created, since it gets more updates (ActionBarSherlock is no longer being developed, link here ) and I think it should cover a lot of functionality.

The problem

All went well (or so it seems), except for a class named ICSLinearLayout on ActionBarSherlock I've used to show dividers on, that is now called LinearLayoutICS .

It just doesn't show the dividers:

enter image description here

Note: before you ask "why don't you just use a GridView?", here's the reason, and also this, in case I'd ever want to add headers.

The code

The code is about the same as I've used for ActionBarSherlock:

rowLayout=new LinearLayoutICS(_context,null);
rowLayout.setMeasureWithLargestChildEnabled(true);
rowLayout.setShowDividers(LinearLayout.SHOW_DIVIDER_MIDDLE);
rowLayout.setDividerDrawable(_context.getResources().getDrawable(R.drawable.list_divider_holo_dark));
rowLayout.setOrientation(LinearLayout.HORIZONTAL);
... // add views, layout params, etc...

The question

How can I use this class in order to support showing dividers on all supported OS versions of the support library?

What is wrong with the code I've written?

Wharton answered 21/3, 2014 at 0:25 Comment(0)
W
0

OK, it seems setShowDividers and setDividerDrawable cannot be used because LinearLayoutICS doesn't have them .

Not only that, but Lint didn't warn me about it being used.

So, what I ended up with is copying LinearLayoutICS code (from here, hope it's the latest version) and some of the original LinearLayout code, to make something that does work. I hope it doesn't have any bugs.

Long live open source ... :)

Sadly setMeasureWithLargestChildEnabled isn't available for old APIs, so I think the ActionBarSherlock way is still better in case that's something you wish to use.

EDIT: the setMeasureWithLargestChildEnabled method doesn't work on ActionBarSherlock.

Here's the code, for those who wish to use. I hope next time the library gets updated, I will remember to check this issue again.

public class LinearLayoutICS extends LinearLayout
  {
  private Drawable mDivider;
  private int      mDividerWidth,mDividerHeight;
  private int      mShowDividers;
  private int      mDividerPadding;

  public LinearLayoutICS(final Context context,final AttributeSet attrs)
    {
    super(context,attrs);
    // the R is from "android.support.v7.appcompat.R" .
    final TypedArray a=context.obtainStyledAttributes(attrs,R.styleable.LinearLayoutICS);
    mDivider=a.getDrawable(R.styleable.LinearLayoutICS_divider);
    if(mDivider!=null)
      {
      mDividerWidth=mDivider.getIntrinsicWidth();
      mDividerHeight=mDivider.getIntrinsicHeight();
      }
    else mDividerHeight=mDividerWidth=0;
    mShowDividers=a.getInt(R.styleable.LinearLayoutICS_showDividers,SHOW_DIVIDER_NONE);
    mDividerPadding=a.getDimensionPixelSize(R.styleable.LinearLayoutICS_dividerPadding,0);
    a.recycle();
    setWillNotDraw(mDivider==null);
    }

  @Override
  protected void onDraw(final Canvas canvas)
    {
    if(getOrientation()==VERTICAL)
      drawDividersVertical(canvas);
    else drawDividersHorizontal(canvas);
    }

  @Override
  protected void measureChildWithMargins(final View child,final int parentWidthMeasureSpec,final int widthUsed,final int parentHeightMeasureSpec,final int heightUsed)
    {
    if(mDivider!=null)
      {
      final int childIndex=indexOfChild(child);
      final int count=getChildCount();
      final LayoutParams params=(LayoutParams)child.getLayoutParams();
      // To display the dividers in-between the child views, we modify their margins
      // to create space.
      if(getOrientation()==VERTICAL)
        {
        if(hasDividerBeforeChildAt(childIndex))
          params.topMargin=mDividerHeight;
        else if(childIndex==count-1&&hasDividerBeforeChildAt(count))
          params.bottomMargin=mDividerHeight;
        }
      else if(hasDividerBeforeChildAt(childIndex))
        params.leftMargin=mDividerWidth;
      else if(childIndex==count-1&&hasDividerBeforeChildAt(count))
        params.rightMargin=mDividerWidth;
      }
    super.measureChildWithMargins(child,parentWidthMeasureSpec,widthUsed,parentHeightMeasureSpec,heightUsed);
    }

  void drawDividersVertical(final Canvas canvas)
    {
    final int count=getChildCount();
    for(int i=0;i<count;i++)
      {
      final View child=getChildAt(i);
      if(child!=null&&child.getVisibility()!=GONE&&hasDividerBeforeChildAt(i))
        {
        final LayoutParams lp=(LayoutParams)child.getLayoutParams();
        drawHorizontalDivider(canvas,child.getTop()-lp.topMargin);
        }
      }
    if(hasDividerBeforeChildAt(count))
      {
      final View child=getChildAt(count-1);
      int bottom=0;
      if(child==null)
        bottom=getHeight()-getPaddingBottom()-mDividerHeight;
      else bottom=child.getBottom();
      drawHorizontalDivider(canvas,bottom);
      }
    }

  void drawDividersHorizontal(final Canvas canvas)
    {
    final int count=getChildCount();
    for(int i=0;i<count;i++)
      {
      final View child=getChildAt(i);
      if(child!=null&&child.getVisibility()!=GONE&&hasDividerBeforeChildAt(i))
        {
        final LayoutParams lp=(LayoutParams)child.getLayoutParams();
        drawVerticalDivider(canvas,child.getLeft()-lp.leftMargin);
        }
      }
    if(hasDividerBeforeChildAt(count))
      {
      final View child=getChildAt(count-1);
      int right=0;
      if(child==null)
        right=getWidth()-getPaddingRight()-mDividerWidth;
      else right=child.getRight();
      drawVerticalDivider(canvas,right);
      }
    }

  void drawHorizontalDivider(final Canvas canvas,final int top)
    {
    mDivider.setBounds(getPaddingLeft()+mDividerPadding,top,getWidth()-getPaddingRight()-mDividerPadding,top+mDividerHeight);
    mDivider.draw(canvas);
    }

  void drawVerticalDivider(final Canvas canvas,final int left)
    {
    mDivider.setBounds(left,getPaddingTop()+mDividerPadding,left+mDividerWidth,getHeight()-getPaddingBottom()-mDividerPadding);
    mDivider.draw(canvas);
    }

  /**
   * Determines where to position dividers between children.
   *
   * @param childIndex Index of child to check for preceding divider
   * @return true if there should be a divider before the child at childIndex
   * @hide Pending API consideration. Currently only used internally by the system.
   */
  protected boolean hasDividerBeforeChildAt(final int childIndex)
    {
    if(childIndex==0)
      return (mShowDividers&SHOW_DIVIDER_BEGINNING)!=0;
    else if(childIndex==getChildCount())
      return (mShowDividers&SHOW_DIVIDER_END)!=0;
    else if((mShowDividers&SHOW_DIVIDER_MIDDLE)!=0)
      {
      boolean hasVisibleViewBefore=false;
      for(int i=childIndex-1;i>=0;i--)
        if(getChildAt(i).getVisibility()!=GONE)
          {
          hasVisibleViewBefore=true;
          break;
          }
      return hasVisibleViewBefore;
      }
    return false;
    }

  @Override
  public int getDividerPadding()
    {
    return mDividerPadding;
    }

  @Override
  public void setDividerPadding(final int dividerPadding)
    {
    mDividerPadding=dividerPadding;
    }

  @Override
  public void setShowDividers(final int showDividers)
    {
    if(mShowDividers!=showDividers)
      requestLayout();
    mShowDividers=showDividers;
    }

  @Override
  public void setDividerDrawable(final Drawable divider)
    {
    if(divider==mDivider)
      return;
    mDivider=divider;
    if(divider!=null)
      {
      mDividerWidth=divider.getIntrinsicWidth();
      mDividerHeight=divider.getIntrinsicHeight();
      }
    else
      {
      mDividerWidth=0;
      mDividerHeight=0;
      }
    setWillNotDraw(divider==null);
    requestLayout();
    }

  @Override
  public Drawable getDividerDrawable()
    {
    return mDivider;
    }
  }
Wharton answered 21/3, 2014 at 9:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.