Skip to content

Commit

Permalink
Added SkippingLastDividerItemDecoration
Browse files Browse the repository at this point in the history
  • Loading branch information
rubo committed Oct 30, 2018
1 parent 75b42dd commit a77f90c
Show file tree
Hide file tree
Showing 4 changed files with 171 additions and 2 deletions.
1 change: 1 addition & 0 deletions Macaron.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
<Compile Include="Resources\Resource.Designer.cs" />
<Compile Include="Utilities\DateTimeExtensions.cs" />
<Compile Include="Utilities\MachineEpsilon.cs" />
<Compile Include="Widgets\SkippingLastDividerItemDecoration.cs" />
<Compile Include="Widgets\SectionedAdapter.cs" />
<Compile Include="Widgets\SelectableAdapter.cs" />
</ItemGroup>
Expand Down
4 changes: 4 additions & 0 deletions NOTICE
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Macaron
Copyright 2018 Ruben Buniatyan

This software contains code derived from The Android Open Source Project (https://source.android.com).
4 changes: 2 additions & 2 deletions Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,5 @@
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyInformationalVersion("1.0.2")]
[assembly: AssemblyVersion("1.0.2.*")]
[assembly: AssemblyInformationalVersion("1.1.0")]
[assembly: AssemblyVersion("1.1.0.*")]
164 changes: 164 additions & 0 deletions Widgets/SkippingLastDividerItemDecoration.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
// Copyright 2018 Ruben Buniatyan
// Licensed under the MIT License. For full terms, see LICENSE in the project root.

using System;
using Android.Content;
using Android.Graphics;
using Android.Graphics.Drawables;
using Android.OS;
using Android.Support.V7.Widget;
using Android.Util;
using Android.Views;
using Android.Widget;

namespace Macaron.Widgets
{
/// <summary>
/// SkippingLastDividerItemDecoration is a <see cref="RecyclerView.ItemDecoration"/> that can be used as a divider
/// between items of a <see cref="LinearLayoutManager"/>. It doesn't decorate the last item.
/// It supports both horizontal and vertical orientations.
/// </summary>
public class SkippingLastDividerItemDecoration : RecyclerView.ItemDecoration
{
#region Fields
private static readonly int[] Attrs = { Android.Resource.Attribute.ListDivider };

private readonly Rect _bounds = new Rect();
private Drawable _divider;
private Orientation _orientation;
#endregion

#region Constructor
/// <summary>
/// Creates a divider <see cref="RecyclerView.ItemDecoration"/> that can be used with a <see cref="LinearLayoutManager"/>.
///
/// </summary>
/// <param name="context">Current context, it will be used to access resources.</param>
/// <param name="orientation">Divider orientation.</param>
public SkippingLastDividerItemDecoration(Context context, Orientation orientation)
{
using (var a = context.ObtainStyledAttributes(Attrs))
{
_divider = a.GetDrawable(0);

if (_divider == null)
Log.Warn("DividerItem", "@android:attr/listDivider was not set in the theme used for this DividerItemDecoration. Please set that attribute all call SetDrawable()");

a.Recycle();
}

SetOrientation(orientation);
}
#endregion

public override void GetItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state)
{
if (_divider == null)
{
outRect.SetEmpty();
return;
}

if (_orientation == Orientation.Vertical)
outRect.Set(0, 0, 0, _divider.IntrinsicHeight);
else
outRect.Set(0, 0, _divider.IntrinsicWidth, 0);
}

public override void OnDraw(Canvas c, RecyclerView parent, RecyclerView.State state)
{
if (parent.GetLayoutManager() == null || _divider == null)
return;

if (_orientation == Orientation.Vertical)
DrawVertical(c, parent);
else
DrawHorizontal(c, parent);
}

private void DrawHorizontal(Canvas canvas, RecyclerView parent)
{
canvas.Save();

int top;
int bottom;

if (parent.ClipToPadding)
{
top = parent.PaddingTop;
bottom = parent.Height - parent.PaddingBottom;

canvas.ClipRect(parent.PaddingLeft, top, parent.Width - parent.PaddingRight, bottom);
}
else
{
top = 0;
bottom = parent.Height;
}

for (int i = 0, count = parent.ChildCount - 1; i < count; i++)
{
var child = parent.GetChildAt(i);

parent.GetLayoutManager().GetDecoratedBoundsWithMargins(child, _bounds);

var right = _bounds.Right + (int)Math.Round(child.TranslationX);
var left = right - _divider.IntrinsicWidth;

_divider.SetBounds(left, top, right, bottom);
_divider.Draw(canvas);
}

canvas.Restore();
}

private void DrawVertical(Canvas canvas, RecyclerView parent)
{
canvas.Save();

int left;
int right;

if (Build.VERSION.SdkInt < BuildVersionCodes.Lollipop || parent.ClipToPadding)
{
left = parent.PaddingLeft;
right = parent.Width - parent.PaddingRight;

canvas.ClipRect(left, parent.PaddingTop, right, parent.Height - parent.PaddingBottom);
}
else
{
left = 0;
right = parent.Width;
}

for (int i = 0, count = parent.ChildCount - 1; i < count; i++)
{
var child = parent.GetChildAt(i);

parent.GetDecoratedBoundsWithMargins(child, _bounds);

var bottom = _bounds.Bottom + (int)Math.Round(child.TranslationY);
var top = bottom - _divider.IntrinsicHeight;

_divider.SetBounds(left, top, right, bottom);
_divider.Draw(canvas);
}

canvas.Restore();
}

/// <summary>
/// Sets the <see cref="Drawable"/> for this divider.
/// </summary>
/// <param name="drawable">Drawable that should be used as a divider.</param>
public void SetDrawable(Drawable drawable) => _divider = drawable ?? throw new ArgumentNullException(nameof(drawable));

/// <summary>
/// Sets the orientation for this divider.
/// This should be called if <see cref="RecyclerView.LayoutManager"/> changes orientation.
/// </summary>
/// <param name="orientation">Divider orientation.</param>
public void SetOrientation(Orientation orientation) => _orientation = orientation;
}
}

0 comments on commit a77f90c

Please sign in to comment.