编辑(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(); }
最近我回到了这个特性/增强,开始开发一个新的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();}
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还将有专家说它让你轻易泄露上下文保持静态引用时一个绘图。