提交 7ca2e4fb 编写于 作者: A Adam Barth

Improve drawer performance

 - Instead of using a ColorFilter or an Opacity widget to colorize the Icons,
   add a ColorFilter parameter it the image classes. This avoids needing to
   call saveLayer for each DrawerItem.
 - Ask Android for unbuffered input events to avoid bad synchronization with
   vsync.

R=ianh@google.com

Review URL: https://codereview.chromium.org/1236043004 .
上级 4ce0e438
......@@ -1249,8 +1249,10 @@ class RenderViewport extends RenderBox with RenderObjectWithChildMixin<RenderBox
class RenderImage extends RenderBox {
RenderImage(sky.Image image, Size requestedSize)
: _image = image, _requestedSize = requestedSize;
RenderImage(sky.Image image, Size requestedSize, { sky.ColorFilter colorFilter })
: _image = image,
_requestedSize = requestedSize,
_colorFilter = colorFilter;
sky.Image _image;
sky.Image get image => _image;
......@@ -1274,6 +1276,26 @@ class RenderImage extends RenderBox {
markNeedsLayout();
}
sky.ColorFilter _colorFilter;
sky.ColorFilter get colorFilter => _colorFilter;
void set colorFilter (sky.ColorFilter value) {
if (value == _colorFilter)
return;
_colorFilter = value;
_cachedPaint = null;
markNeedsPaint();
}
Paint _cachedPaint;
Paint get _paint {
if (_cachedPaint == null) {
_cachedPaint = new Paint();
if (colorFilter != null)
_cachedPaint.setColorFilter(colorFilter);
}
return _cachedPaint;
}
Size _sizeForConstraints(BoxConstraints innerConstraints) {
// If there's no image, we can't size ourselves automatically
if (_image == null) {
......@@ -1350,7 +1372,7 @@ class RenderImage extends RenderBox {
canvas.scale(widthScale, heightScale);
offset = Offset.zero;
}
canvas.drawImage(_image, offset.toPoint(), new Paint());
canvas.drawImage(_image, offset.toPoint(), _paint);
if (needsScale)
canvas.restore();
}
......
......@@ -485,28 +485,32 @@ class Text extends Component {
}
class Image extends LeafRenderObjectWrapper {
Image({ sky.Image image, this.size })
Image({ sky.Image image, this.size, this.colorFilter })
: image = image,
super(key: image.hashCode.toString()); // TODO(ianh): Find a way to uniquely identify the sky.Image rather than using hashCode, which could collide
final sky.Image image;
final Size size;
final sky.ColorFilter colorFilter;
RenderImage createNode() => new RenderImage(image, size);
RenderImage createNode() => new RenderImage(image, size, colorFilter: colorFilter);
RenderImage get root => super.root;
void syncRenderObject(Widget old) {
super.syncRenderObject(old);
root.image = image;
root.requestedSize = size;
root.colorFilter = colorFilter;
}
}
class FutureImage extends StatefulComponent {
FutureImage({ String key, this.image, this.size }) : super(key: key);
FutureImage({ String key, this.image, this.size, this.colorFilter })
: super(key: key);
Future<sky.Image> image;
Size size;
sky.ColorFilter colorFilter;
sky.Image _resolvedImage;
......@@ -534,34 +538,44 @@ class FutureImage extends StatefulComponent {
}
Widget build() {
return new Image(image: _resolvedImage, size: size);
return new Image(image: _resolvedImage, size: size, colorFilter: colorFilter);
}
}
class NetworkImage extends Component {
NetworkImage({ String src, this.size })
NetworkImage({ String src, this.size, this.colorFilter })
: src = src,
super(key: src);
final String src;
final Size size;
final sky.ColorFilter colorFilter;
Widget build() {
return new FutureImage(image: image_cache.load(src), size: size);
return new FutureImage(
image: image_cache.load(src),
size: size,
colorFilter: colorFilter
);
}
}
class AssetImage extends Component {
AssetImage({ String name, this.bundle, this.size })
AssetImage({ String name, this.bundle, this.size, this.colorFilter })
: name = name,
super(key: name);
final String name;
final AssetBundle bundle;
final Size size;
final sky.ColorFilter colorFilter;
Widget build() {
return new FutureImage(image: bundle.loadImage(name), size: size);
return new FutureImage(
image: bundle.loadImage(name),
size: size,
colorFilter: colorFilter
);
}
}
......
......@@ -46,26 +46,24 @@ class DrawerItem extends ButtonBase {
return colors.transparent;
}
sky.ColorFilter _getColorFilter(ThemeData themeData) {
if (selected)
return new sky.ColorFilter.mode(themeData.primaryColor, sky.TransferMode.srcATop);
return new sky.ColorFilter.mode(const Color(0x73000000), sky.TransferMode.dstIn);
}
Widget buildContent() {
ThemeData themeData = Theme.of(this);
List<Widget> flexChildren = new List<Widget>();
if (icon != null) {
Widget child = new Icon(type: icon, size: 24);
if (selected) {
child = new ColorFilter(
color: themeData.primaryColor,
transferMode: sky.TransferMode.srcATop,
child: child
);
}
flexChildren.add(
new Opacity(
opacity: selected ? 1.0 : 0.45,
child: new Padding(
padding: const EdgeDims.symmetric(horizontal: 16.0),
child: child
)
new Padding(
padding: const EdgeDims.symmetric(horizontal: 16.0),
child: new Icon(
type: icon,
size: 24,
colorFilter: _getColorFilter(themeData))
)
);
}
......
......@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:sky' as sky;
import 'package:sky/mojo/asset_bundle.dart';
import 'package:sky/widgets/basic.dart';
import 'package:sky/widgets/theme.dart';
......@@ -46,11 +48,18 @@ AssetBundle _initIconBundle() {
final AssetBundle _iconBundle = _initIconBundle();
class Icon extends Component {
Icon({ String key, this.size, this.type: '', this.color }) : super(key: key);
Icon({
String key,
this.size,
this.type: '',
this.color,
this.colorFilter
}) : super(key: key);
final int size;
final String type;
final IconThemeColor color;
final sky.ColorFilter colorFilter;
String get colorSuffix {
IconThemeColor iconThemeColor = color;
......@@ -84,7 +93,8 @@ class Icon extends Component {
return new AssetImage(
bundle: _iconBundle,
name: '${category}/${density}/ic_${subtype}_${colorSuffix}_${size}dp.png',
size: new Size(size.toDouble(), size.toDouble())
size: new Size(size.toDouble(), size.toDouble()),
colorFilter: colorFilter
);
}
}
......@@ -56,6 +56,8 @@ struct GestureData {
float velocityY;
};
// TODO(abarth): Should we have a malloc-free way of creating an input event
// message? What we have now could stress out the Android Java GC.
struct InputEvent {
EventType type;
int64 time_stamp;
......
......@@ -5,6 +5,7 @@
package org.domokit.sky.shell;
import android.content.Context;
import android.os.Build;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.SurfaceHolder;
......@@ -170,15 +171,23 @@ public class PlatformViewAndroid extends SurfaceView
inputEvent.timeStamp = event.getEventTime();
inputEvent.pointerData = pointerData;
mSkyEngine.onInputEvent(inputEvent);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
// TODO(abarth): This version check might not be effective in some
// versions of Android that statically compile code and will be upset
// at the lack of |requestUnbufferedDispatch|. Instead, we should factor
// version-dependent code into separate classes for each supported
// version and dispatch dynamically.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
requestUnbufferedDispatch(event);
}
mGestureProvider.onTouchEvent(event);
// TODO(abarth): Rather than unpacking these events here, we should
// probably send them in one packet to the engine.
int maskedAction = event.getActionMasked();
// ACTION_UP, ACTION_POINTER_UP, ACTION_DOWN, and ACTION_POINTER_DOWN
// only apply to a single pointer, other events apply to all pointers.
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册