编辑(11/27/12):添加一个视频演示结果在Nexus 7运行Android 4.1系统
过去一年,ActionBar范式已经成为一个重要的组成部分的过程中,设计和开发一个Android应用程序。事实上,有许多优点,ActionBar帮助开发人员在其应用程序能否经得住时间的考验。它包含相关操作,可以很容易地定制,是高度可伸缩的,等等。正因为如此,一个人应该总是考虑使用ActionBar UI模式在设计过程在创建一个新的Android应用程序。
ActionBar功能很多有趣的样式的api。这些api允许您品牌你应用程序,这样,适合你的设计,同时还被辨认在其他的应用程序。简单来说,就是几乎没有限制你能做什么和一个ActionBar。直到你尝试做一些更高级的。。。
为了确保这是可能我创建了一个小小的应用程序与一个ActionBar。我迅速建立了一个AnimationDrawable,开始用一个简单的调用start()方法,并使用它作为ActionBar的背景。结果很令人失望,因为它不是在所有动画。探索ActionBarContainer(一个非公有制视图支持ActionBar)源代码我注意到它没有登记callback1我可拉的:
public void setPrimaryBackground(Drawable bg) {
mBackground = bg;
invalidate();
}
结果,可拉的没有办法通知封闭视图以固定时间间隔重绘本身。从我的角度来看,这是一个想要的行为,以避免这些web -的- - - - 90的红色到黄色闪烁ActionBars。我终于决定推迟到未来版本的动画。
最近我回到了这个特性/增强,开始开发一个新的Animatable可提取测试目的。这个非常基本的绘图改变颜色和变化的变化在一个光滑的时尚:
public class ColorAnimationDrawable extends Drawable implements Animatable {
private static final long FRAME_DURATION = 1000 / 60;
private static final long ANIMATION_DURATION = 1500;
private static final int ACCCENT_COLOR = 0x33FFFFFF;
private static final int DIM_COLOR = 0x33000000;
private static final Random mRandom = new Random();
private final Paint mPaint = new Paint();
private boolean mIsRunning;
private int mStartColor;
private int mEndColor;
private int mCurrentColor;
private long mStartTime;
@Override
public void draw(Canvas canvas) {
final Rect bounds = getBounds();
mPaint.setColor(mCurrentColor);
canvas.drawRect(bounds, mPaint);
mPaint.setColor(ACCCENT_COLOR);
canvas.drawRect(bounds.left, bounds.top, bounds.right, bounds.top + 1, mPaint);
mPaint.setColor(DIM_COLOR);
canvas.drawRect(bounds.left, bounds.bottom - 2, bounds.right, bounds.bottom, mPaint);
}
@Override
public void setAlpha(int alpha) {
oops("setAlpha(int)");
}
@Override
public void setColorFilter(ColorFilter cf) {
oops("setColorFilter(ColorFilter)");
}
@Override
public int getOpacity() {
return PixelFormat.TRANSPARENT;
}
@Override
public void start() {
if (!isRunning()) {
mIsRunning = true;
mStartTime = AnimationUtils.currentAnimationTimeMillis();
mStartColor = randomColor();
mEndColor = randomColor();
scheduleSelf(mUpdater, SystemClock.uptimeMillis() + FRAME_DURATION);
invalidateSelf();
}
}
@Override
public void stop() {
if (isRunning()) {
unscheduleSelf(mUpdater);
mIsRunning = false;
}
}
@Override
public boolean isRunning() {
return mIsRunning;
}
private void oops(String message) {
throw new UnsupportedOperationException("ColorAnimationDrawable doesn't support " + message);
}
private static int randomColor() {
return mRandom.nextInt() & 0x00FFFFFF;
}
private static int evaluate(float fraction, int startValue, int endValue) {
return (int) (startValue + fraction * (endValue - startValue));
}
private final Runnable mUpdater = new Runnable() {
@Override
public void run() {
long now = AnimationUtils.currentAnimationTimeMillis();
long duration = now - mStartTime;
if (duration >= ANIMATION_DURATION) {
mStartColor = mEndColor;
mEndColor = randomColor();
mStartTime = now;
mCurrentColor = mStartColor;
} else {
float fraction = duration / (float) ANIMATION_DURATION;
//@formatter:off
mCurrentColor = Color.rgb(
evaluate(fraction, Color.red(mStartColor), Color.red(mEndColor)), // red
evaluate(fraction, Color.green(mStartColor), Color.green(mEndColor)), // green
evaluate(fraction, Color.blue(mStartColor), Color.blue(mEndColor))); // blue
//@formatter:on
}
scheduleSelf(mUpdater, SystemClock.uptimeMillis() + FRAME_DURATION);
invalidateSelf();
}
};
}
我认为唯一有趣的事情在这段代码是使用的方法来激活一个颜色变化。它由提取每个颜色分量和动画这些值,而不是整个颜色。
我申请这个可拉的我和boooom ActionBar是工作!我很惊讶,开始调查。在看AOSP源代码果冻豆MR1释放,我注意到,这一问题被固定由亚当·鲍威尔(一个工程师在谷歌工作的UI工具包)与a7cc06d。现在的代码如下所述:
public void setPrimaryBackground(Drawable bg) { if (mBackground != null) { mBackground.setCallback(null); unscheduleDrawable(mBackground); } mBackground = bg; if (bg != null) { bg.setCallback(this); } setWillNotDraw(mIsSplit ? mSplitBackground == null : mBackground == null && mStackedBackground == null); invalidate();}
这个问题,这种修复是它不是用于预api 17构建。所以我想出了一个很简单的解决办法,为pre api 17:注册一个自定义的绘图。回调,使ActionBarContainer反复设置相同的绘图与ActionBar的setBackgroundDrawable(绘图)方法:
public class MainActivity extends Activity {
private final Handler mHandler = new Handler();
private ColorAnimationDrawable mActionBarBackground;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
mActionBarBackground = new ColorAnimationDrawable();
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
mActionBarBackground.setCallback(mDrawableCallback);
} else {
getActionBar().setBackgroundDrawable(mActionBarBackground);
}
mActionBarBackground.start();
}
@Override
protected void onResume() {
super.onResume();
mActionBarBackground.start();
}
@Override
protected void onPause() {
super.onPause();
mActionBarBackground.stop();
}
private Drawable.Callback mDrawableCallback = new Drawable.Callback() {
@Override
public void invalidateDrawable(Drawable who) {
getActionBar().setBackgroundDrawable(who);
}
@Override
public void scheduleDrawable(Drawable who, Runnable what, long when) {
mHandler.postAtTime(what, when);
}
@Override
public void unscheduleDrawable(Drawable who, Runnable what) {
mHandler.removeCallbacks(what);
}
};
}
多亏了这个技巧,你现在可以激活你的背景ActionBar回到API 11但请记住这可能有几个,有时严重的后果在你的应用程序:它可以让你的应用程序看起来不同和更加优美的特色是微小的,微妙的和漂亮的细节
当设置一个动画背景一个ActionBar,总是确保尽可能是微妙的。动画不应干扰或中断用户在他/她与你的应用程序的交互,比如你可以运行动画只有当用户不触及你的活动。 使用本文中描述的技术力量系统失效整个ActionBarContainer对于每个动画帧。减少你的动画的持续时间尽可能多的CPU和GPU消费
动画背景可拉的不应该是一些必要的程序。可拉的只能作为样式组件而不是交互组件。
我可以写一整本书的章可拉的概念。把简单,当设置绘图作为一个视图的背景,视图注册自己是可拉的的回调。这让绘图视图无效它属于。换句话说,它允许您创建画板,可以刷新/重画自己。Android还将有专家说它让你轻易泄露上下文保持静态引用时一个绘图。