How to Apply a Global Grayscale Theme to Android Apps Using Custom Views
This article demonstrates how to achieve a global grayscale (black‑and‑white) effect in Android applications by adding simple CSS‑like styles for web pages and creating custom ImageView, TextView, Button, LinearLayout, FrameLayout subclasses that override draw and dispatchDraw methods, and integrating them via Activity onCreateView to replace the default content view.
On April 4 many websites and apps turned black‑and‑white to mourn, and the author shows how to implement the same effect purely with technology.
For a web page, a single CSS rule adds a grayscale filter to the whole page:
html {filter:progid:DXImageTransform.Microsoft.BasicImage(grayscale=1); -webkit-filter: grayscale(100%);}In Android, the same idea can be applied by creating custom views that modify the canvas drawing.
GrayImageView extends AppCompatImageView and overrides draw(Canvas canvas) to apply a ColorMatrix with zero saturation:
public class GrayImageView extends AppCompatImageView {
private Paint mPaint = new Paint();
public GrayImageView(Context context, AttributeSet attrs) {
super(context, attrs);
ColorMatrix cm = new ColorMatrix();
cm.setSaturation(0);
mPaint.setColorFilter(new ColorMatrixColorFilter(cm));
}
@Override
public void draw(Canvas canvas) {
canvas.saveLayer(null, mPaint, Canvas.ALL_SAVE_FLAG);
super.draw(canvas);
canvas.restore();
}
}The layout file simply places a normal ImageView and the custom GrayImageView for comparison.
Similarly, GrayTextView and GrayButton are created by extending AppCompatTextView and AppCompatButton with the same paint logic, showing that any widget can be grayed.
To avoid replacing every view individually, a GrayLinearLayout is introduced. By overriding both draw and dispatchDraw , all child views inherit the grayscale effect:
public class GrayLinearLayout extends LinearLayout {
private Paint mPaint = new Paint();
public GrayLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
ColorMatrix cm = new ColorMatrix();
cm.setSaturation(0);
mPaint.setColorFilter(new ColorMatrixColorFilter(cm));
}
@Override
public void draw(Canvas canvas) {
canvas.saveLayer(null, mPaint, Canvas.ALL_SAVE_FLAG);
super.draw(canvas);
canvas.restore();
}
@Override
protected void dispatchDraw(Canvas canvas) {
canvas.saveLayer(null, mPaint, Canvas.ALL_SAVE_FLAG);
super.dispatchDraw(canvas);
canvas.restore();
}
}Replacing the activity’s root layout with GrayLinearLayout instantly grays the whole UI.
For a more universal solution, the author replaces the system android:id/content FrameLayout with a custom GrayFrameLayout by overriding Activity.onCreateView . The method detects when a FrameLayout with the content ID is being inflated and returns a GrayFrameLayout instance instead.
@Override
public View onCreateView(String name, Context context, AttributeSet attrs) {
if ("FrameLayout".equals(name)) {
int count = attrs.getAttributeCount();
for (int i = 0; i < count; i++) {
String attrName = attrs.getAttributeName(i);
String attrValue = attrs.getAttributeValue(i);
if (attrName.equals("id")) {
int id = Integer.parseInt(attrValue.substring(1));
String idVal = getResources().getResourceName(id);
if ("android:id/content".equals(idVal)) {
GrayFrameLayout gray = new GrayFrameLayout(context, attrs);
return gray;
}
}
}
}
return super.onCreateView(name, context, attrs);
}The GrayFrameLayout uses the same paint‑based grayscale logic and also forwards background handling so that window backgrounds are also affected.
Additional notes cover handling of window background drawables, dialog support (which works automatically because dialogs are also part of the view hierarchy), and potential future changes where android:id/content might not be a FrameLayout .
Finally, the author demonstrates the effect on a real project (WanAndroid) where the entire app—including WebView content—appears in grayscale, confirming the approach works across complex UI structures.
Sohu Tech Products
A knowledge-sharing platform for Sohu's technology products. As a leading Chinese internet brand with media, video, search, and gaming services and over 700 million users, Sohu continuously drives tech innovation and practice. We’ll share practical insights and tech news here.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.