Summary
Drawing between a View’s background and its contents in Android is challenging when you don’t own the View or Drawable. The key issue is the lack of direct hooks or listeners to intercept the drawing process at the desired z-order. Common solutions like subclassing, wrapping, or using Drawable callbacks are not feasible due to constraints.
Root Cause
- No direct access to the drawing pipeline: Android’s
ViewandDrawableAPIs do not provide a way to insert custom draw operations between the background and content. - Runtime constraints: Extending classes or modifying existing Drawables is prohibited.
- Limited z-order control:
View.setForeground()and overlays draw above the content, not between background and content.
Why This Happens in Real Systems
- Encapsulation: Android’s framework prioritizes encapsulation, limiting direct manipulation of internal drawing processes.
- Performance considerations: Allowing arbitrary draw interceptions could introduce inefficiencies or inconsistencies.
- API design: The
ViewandDrawableAPIs were not designed with this specific use case in mind.
Real-World Impact
- Inability to achieve desired visual effects: Libraries or apps requiring precise z-order control (e.g., highlighting text in a
TextView) are blocked. - Workarounds are intrusive: Solutions like wrapping Views or modifying Drawables can break user code or interfere with interactions.
- Limited library functionality: Runtime appearance modification libraries face significant limitations in Android.
Example or Code (if necessary and relevant)
// Example of a failed attempt using View.setForeground()
val view = findViewById(R.id.textView)
val foregroundDrawable = ColorDrawable(Color.YELLOW)
view.foreground = foregroundDrawable // Draws above content, not between background and content
How Senior Engineers Fix It
- Leverage
Viewhierarchy: Use a transparentViewGroupwith custom drawing in itsdispatchDraw()method to intercept and modify the drawing process. - Reflective access: Use reflection to access and modify internal
Drawablestates or drawing methods (caution: not recommended due to instability). - Custom
Viewwrapper: Create a non-intrusive wrapper that captures and modifies the drawing canvas, though this may violate constraints.
Why Juniors Miss It
- Overlooking
dispatchDraw(): Juniors often focus ononDraw()and miss the opportunity to intercept drawing in a parentViewGroup. - Misunderstanding z-order: Confusion between
View.setForeground(), overlays, and the actual drawing order. - Ignoring framework limitations: Underestimating the constraints imposed by Android’s encapsulation and API design.