Repository navigation
HexGridView
Package: com.gonodono.hexgrid.view
HexGridView is the View version of the library's grid UI. It's actually
a ViewGroup, and is designed to allow adding children either in layout XML, or
in code through a specialized interface.
HexGridView can be set up completely through its layout XML, and it recognizes
several special attributes on itself and its children in order to allow for
that. All attributes in the snippet below belong to the library, and are shown
with their default values. I'm not a big fan of projects that slap a common
prefix and underscore on every custom attribute, so I've avoided that here, but
several of them do share somewhat descriptive prefixes that have been added in
an attempt to avoid name collisions with the platform and other standard
libraries.
<com.gonodono.hexgrid.view.HexGridView
…
app:gridRowCount="0"
app:gridColumnCount="0"
app:insetEvenLines="false"
app:enableEdgeLines="false"
app:fitMode="fitColumns"
app:crossMode="alignCenter"
app:hexOrientation="horizontal"
app:cellStrokeWidth="0dp"
app:cellStrokeColor="@color/black"
app:cellFillColor="@color/transparent"
app:cellSelectColor="@color/light_gray"
app:cellIndicesShown="none">
<com.gonodono.hexgrid.view.CellStateView
…
app:layout_cellRowAndColumn="0,0"
app:layout_cellIsVisible="true"
app:layout_cellIsSelected="false"
app:layout_hexBackgroundEnabled="false"
app:layout_hexBackgroundColor="@color/transparent"
app:layout_hexBackgroundInset="0dp" />
</com.gonodono.hexgrid.view.HexGridView>The attributes on the <HexGridView> should be rather self-explanatory, given
the information already provided. The layout_ attributes on the child are in
two groups: those that start with cell that denote and affect the relevant
grid cell, and those that start with hexBackground, which allow for
a HexDrawable to be set as the child's background.
HexDrawable is a simple class that sets a hexagonal Outline – which allows
it to cast appropriately shaped shadows – and fills it with a solid color. The
class is open to permit further customizations; e.g., using a Shader instead
of a solid color, inserting a RippleDrawable, etc.
Any kind of normal child View can be used with HexGridView. The library also
offers the custom CellStateView, which can be used to apply cell attributes
to the grid without adding an actual View instance at runtime. Since no child
is added, the hexBackground attributes are useless on a <CellStateView>. The
XML above is only for show.
Setup in code is a little different than you might expect from the available
attributes. As previously mentioned, the row count, the column count, which
lines to inset, and whether to enable edge lines are the four things that define
a Grid, and HexGridView handles those things altogether through its
single var grid: Grid property, since changing any of them defines a new grid
anyway.
The View version's implementation of Grid is MutableGrid, which allows
(only) the Grid.States to be changed for each of the predefined
Grid.Addresses. (Mutable probably isn't the most appropriate descriptor for
this, but Changeable or something similar would be unwieldy and confusing.) To
effect this functionality, MutableGrid has an additional set indexed
accessor.
val mutableGrid = MutableGrid(3, 3, insetEvenLines = true)
mutableGrid.change(Grid.Address(0, 1), isSelected = true)
hexGridView.grid = mutableGrid
hexGridView.viewProvider = HexGridView.ViewProvider { address, current ->
val image = current as? ImageView ?: ImageView(context).apply {
setImageResource(R.drawable.example)
}
image.imageTintList = when {
mutableGrid[address].isSelected -> ColorStateList.valueOf(Color.CYAN)
else -> null
}
image
}Grids behave like Lists used with ListViews or RecyclerViews: they are
inert collections that simply hold state. The HexGridView needs to be notified
if you change a Grid externally, and since it's only a draw change,
calling invalidate() is sufficient, so I leave that to the user. I'm not going
to complicate things by defining some relay function
like notifyDataSetChanged() that calls invalidate() and does nothing else.
To illustrate:
hexGridView.onClickListener = HexGridView.OnClickListener { address ->
mutableGrid.toggle(address)
hexGridView.invalidate()
}The MutableGrid.toggle(address: Grid.Address) extension function replaces
the Grid.State at address with a copy that has the opposite isSelected
value. You can do it manually, if you like, but it's tedious.
The library also includes the HexGridDrawable class in the view package to
allow a non-interactive version of the hex grid to be used wherever a Drawable
can be applied. It has the same basic functionality as HexGridView, with a few
differences:
- It does not support child
Views in its cells. - It has no click handler interface, since
Drawables are inherently non-interactive. - It always uses its assigned bounds; i.e., it cannot
wrap_contentin the cross dimension.
NB: Don't confuse HexGridDrawable with HexDrawable. The latter is for use
only with HexGridView, to provide shaped backgrounds for its child items.