I have a custom drawable for my action bar which extends GradientDrawable. I the drawable itself draws exactly what I want, my issue seems to be WHEN it draws. I developed it on Nexus devices and it works great, exactly as expected, however, when I run it on non-nexus devices it does not function properly. I traced it back to the draw(Canvas canvas) call not being called at the same rate as Nexus devices. I added a line of code which replaces the action bar drawable with the same drawable after adjusting its settings and this made it work on all devices but I don’t like constantly resetting the drawable as it happens as the user drags across a screen. Is this simply not a concern? Do the manufacturers really get to modify the drawing system that much? Any ideas? Device results and code are included below.
The drawable’s draw() method
/*
* mUnderlineColor, mUnderlineWidth, mToplineColor and mToplineWidth are all
* parameters which change as the user drags. The methods to set them call
* invalidateSelf() after changing the values in the corresponding paints
*/
public void draw(Canvas canvas) {
super.draw(canvas);
if (Color.alpha(mUnderlineColor) != 0) {
canvas.drawLine(0, canvas.getHeight()-mUnderlineWidth+1, canvas.getWidth(),
canvas.getHeight()-mUnderlineWidth+1, mUnderlinePaint);
}
canvas.drawLine(0, mToplineWidth-1, canvas.getWidth(), mToplineWidth-1, mToplinePaint);
}
public void setUnderlineAlpha(float alpha) {
mUnderlineColor = Color.argb(Math.round(alpha * 255), Color.red(mUnderlineColor),
Color.green(mUnderlineColor), Color.blue(mUnderlineColor));
mUnderlinePaint.setColor(mUnderlineColor);
invalidateSelf();
}
Setting the parameters
public void onPageScroll(int xpos) {
float alpha = mWidthPercentage - (float)xpos / mScreenWidthPixels;
mFadingUnderline = alpha / mWidthPercentage;
int actionBarAlpha = 200 + Math.round((255 - 200) * mFadingUnderline);
mDrawable.setAlpha(actionBarAlpha);
mDrawable.setUnderlineAlpha(mFadingUnderline);
//mActionBar.setBackgroundDrawable(mDrawable);
//The commented line is unnecessary on Nexus devices, but required on
//everything else.
}
Devices that do not need me to call setBackgroundDrawable()*
- Galaxy Nexus (4.2.1)
- Nexus 10 (4.2.1)
- Nexus 7 (4.2.1)
- Nexus S (4.2)
- Motorola Xoom (4.0.4)
Devices that do require me to call setBackgroundDrawable()*
- Transformer Prime (4.1.1)
- Galaxy Tab 7.0+ (4.0.4)
- Acer A500 (4.0.3)
If there is no overhead of resetting the drawable I don’t mind so much, it just seems odd to me that Nexus devices all draw after invalidateSelf() and the manufacturer devices don’t. Anyone have some input?
invalidateSelf()only performs redrawing if the Drawable’s callback is set. I imagine on the devices where it succeeds agetCallback()would be non-null and on failures it would be null. Why? You got me.The reason a new call to
setBackgroundDrawable()works is that that causes theActionBarto invalidate itself. Instead of refreshing, you could bypass and have theActionBarinvalidate manually. Don’t think it matters too much.