-
Notifications
You must be signed in to change notification settings - Fork 5
Notes
- General
- Views
- Compose
If you notice odd gaps or spaces between shadows and their targets, especially
those with irregular shapes, particularly along their lower edges while at the
bottom of their Window, it's likely not due to this library, though this may
have made the issue more noticeable.
I'm not sure of the exact cause so I won't go into any details here, but I would
point you to this question on Stack Overflow that illustrates
the issue, and has an answer of mine that gives a few workaround options. We're
talking about Views there but the same outline adjustment can be applied in
Compose as well using GenericShape.
This is a problem with the native shadows so the library does nothing to address it. I mention it for those who might notice the issue while using the library and suspect that something here could be the cause. Also, certain examples in the demo app – e.g., the popups on the pages for the root topics – seem prone to suffering this defect, especially on larger screens.
The library's clip fix is not necessary if the target's background and the region behind it are each a single simple color. In that case, it is preferable to calculate the opaque color that results from compositing the translucent one over the other, then set that as the target's background instead.
-
Compose already has the
compositeOver()function in itsandroidx.compose.ui.graphics.Colorclass that can do the necessary calculations internally. -
The View framework has no such function out of the box, but this extension from the androidx test source shows how to do the math for
android.graphics.Color.
If you only need the clip fix for relatively simple setups, you might prefer to put something together from the independent solutions demonstrated in the following Stack Overflow posts. If those basic examples are sufficient for your design, you probably don't want the overhead here.
-
The View version is covered in this answer. The two techniques shown there are the library's primary and fallback functionalities for this framework.
As is, the given setup works only with static shadows. If you need to handle buttons presses or animations or the like, you'll have to hook up a
ViewTreeObserver.OnPreDrawListenerto manually invalidate when a target is modified. -
The Compose solution is in this answer, and it also is quite similar to the library's implementation for Composables, lacking only color compat.
As a
Modifierand extension, it is a drop-in replacement forshadow().
Much of the library's internal workings rely on or otherwise involve a target's parent or root ancestor. Since those don't really exist if the target is the root of its hierarchy, there are restrictions for use on such elements.
-
For Views, both of the library's fixes can be used on ones at the root of their respective hierarchies, but only with a specific configuration: using the
Inlineplane with the root'sclipToOutlineset tofalse.If you plan to use this with an
ActivityorDialog, be aware that theirWindows' styles usually set the decor (root)View'sclipToOutline = true, so you'll likely have to disable that yourself. It can be done either through theandroid:windowClipToOutlinetheme attribute, or in code through the decor'sclipToOutlineor theWindow'ssetClipToOutline().There is one particular setup that is problematic: non-
ViewGrouproots, e.g.,ImageViews added directly toWindowManager. On API levels 21..27, library shadows are not possible here if the fallback draw method is in use, and on API level 28, they don't work here at all. A new stateenumand helper extension have been added to allow for user fallbacks:ShadowModeandView.doOnShadowModeChange. Details can be found on the Experimental wiki page. -
For Compose, any root
Composableon Android is (effectively) the only child of itsComposeView, which it fills completely.The clip fix by itself will work on a root
Composableas long as theComposeViewis not being clipped to its outline or bounds. Specifically, theComposeViewitself must haveclipToOutlineset tofalse(the default), and its parentViewGroup, if there is one, must haveclipChildrenset tofalseas well.Using color compat here isn't currently possible, since the compositing layers are sized to a target's root
Composable. This could conceivably be updated to fix that, but I don't think it's worth the effort for this feature that is quickly becoming obsolete as projects update theirminSdks to 28 and beyond. The:viewmodule's color compat can be applied to theComposeViewinstead, if needed.
The native ambient and spot shadow colors are supported on Pie and above, technically. They absolutely do work for Q+, but I cannot get the native shadow colors to work at all on Pie itself, with or without this library involved. All of the relevant methods and attributes were introduced with that version, and the documentation indicates that they should work like normal, but none of the emulators I've tested on show anything but black shadows. I can't find any mention of anyone else having the same issue, though, so I'm completely baffled by this.
The demo app's Intro page has a setup that lets you fiddle with the shadow color, so that could be used as a quick test, if you're curious. It is set up to fall back to the new color compat mechanism for API levels <28, but 28 itself uses the native ambient and spot colors, so the colors will fail on Pie if you observe the same behavior I do.
The Issues feature for this repository is active. Please report bugs and any other problems there, for any version of the library.
Download numbers indicate that many projects are still using old versions. If that's due to unaddressed bugs or other issues in the newer releases, please let me know about them. I'd really appreciate the opportunity to improve things.
The library's particular technique causes a target's parent ViewGroup to be
invalidated more than it normally would. For static shadows, it's just an extra
time or two when switched on or updated. For animated shadows, though, the
parent is invalidated on each step of the animation, no matter the type,
effectively defeating some of the optimizations that hardware acceleration
brings. Button presses, for example, aren't "free" when the button has an active
library shadow.
It's not great, but it's likely not a huge deal for most setups, especially
considering that many animations will cause the same invalidations anyway. The
app in the demo module has several different arrangements that translate and
rotate and such, so you can investigate the effects, if curious.
In order to disable a target's inherent shadow, its ViewOutlineProvider is
wrapped in a custom implementation. This has the possibility of breaking
something if some function or component is expecting the View to have one of
the static platform implementations; i.e., BACKGROUND, BOUNDS, or
PADDED_BOUNDS. This shouldn't cause a fatal error or anything – it's no
different than anything else that uses a custom provider – but you might need to
rework some background drawables or the like.
Additionally, any user implementations of ViewOutlineProvider should be set
before enabling library shadows, or at least before the target attaches to its
Window.
The Recycling ShadowsViewGroups used to have specialized behavior that
optimizes shadow creation and disposal for rapid scrolling. At some point, I
figured out a way to apply that behavior to all RecyclerViews and
AdapterViews, whether they're ShadowsViewGroups or not. At the time,
however, I overlooked the fact that this was creating an irremovable dependency
on RecyclerView. That is, RecyclerView is always referenced in the base
view functionalities, so it cannot be stripped by ProGuard/R8, even if you're
not using it anywhere. Whoops.
This can be corrected without a regression, but the possible solutions are
unwieldy and inelegant. Given that and the fact that RecyclerView usage is
rather ubiquitous these days, I've decided not to do anything about it
preemptively. If you do really, really need that fixed, you can file an
issue for it, and I'll try to figure something out. Otherwise, it
might be easier to clone the repo and remove the single relevant
reference in the ShadowSwitch file.
The ExperimentalColorCompat annotation has been removed from the library.