This works for me (Android 4.1 required):
Switch switchInput = new Switch(this); int colorOn = 0xFF323E46; int colorOff = 0xFF666666; int colorDisabled = 0xFF333333; StateListDrawable thumbStates = new StateListDrawable(); thumbStates.addState(new int[]{android.R.attr.state_checked}, new ColorDrawable(colorOn)); thumbStates.addState(new int[]{-android.R.attr.state_enabled}, new ColorDrawable(colorDisabled)); thumbStates.addState(new int[]{}, new ColorDrawable(colorOff));
Note that the default state must be added last, as shown here.
The only problem I see is that the thumb of the switch is now larger than the background or track of the switch. I think because I am still using the default track image, which has empty space around it. However, when I tried to adjust the image of the track using this technique, my switch apparently had a height of 1 pixel, and only text text on / off. There must be a solution for this, but I have not found it yet ...
Update for Android 5.1
In Android 5.1, the code above disables the switch completely. We should use the new setButtonTintList method, but this had no effect when I tried it. Now I use this code:
switchInput.getThumbDrawable().setColorFilter(Color.RED, PorterDuff.Mode.MULTIPLY); switchInput.getTrackDrawable().setColorFilter(Color.RED, PorterDuff.Mode.MULTIPLY);
The only drawback is that there is no way to set the color for the disabled state. The track becomes paler, but the thumb remains the same color, so the change is more subtle than we would like.
Update for Android 5.1.1
Apparently, the setButtonTintList () method had an error in 5.1, which was fixed in 5.1.1. This code now works as expected, without any flaws that I see:
ColorStateList buttonStates = new ColorStateList( new int[][]{ new int[]{-android.R.attr.state_enabled}, new int[]{android.R.attr.state_checked}, new int[]{} }, new int[]{ Color.BLUE, Color.RED, Color.GREEN } ); switchInput.setButtonTintList(buttonStates);
Update for Android 6-7
In Android 6-7, setButtonTintList ignored on switches. As stated in the comments on Cheruby, we can use the new setThumbTintList and worked as expected for me. We can also use setTrackTintList , but this refers to the color as a mixture, making it darker than expected in dark colors and lighter than expected in light colors, sometimes invisible. In Android 7, I managed to minimize these changes by overriding the tint mode track, but I couldnโt get decent results from Android 6. You may need to define additional colors that compensate for the mix. (Do you ever get the feeling that Google doesn't want us to customize the look of our apps?)
ColorStateList thumbStates = new ColorStateList( new int[][]{ new int[]{-android.R.attr.state_enabled}, new int[]{android.R.attr.state_checked}, new int[]{} }, new int[]{ Color.BLUE, Color.RED, Color.GREEN } ); switchInput.setThumbTintList(thumbStates); if (Build.VERSION.SDK_INT >= 24) { ColorStateList trackStates = new ColorStateList( new int[][]{ new int[]{-android.R.attr.state_enabled}, new int[]{} }, new int[]{ Color.GRAY, Color.LTGRAY } ); switchInput.setTrackTintList(trackStates); switchInput.setTrackTintMode(PorterDuff.Mode.OVERLAY); }