mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
This CL cleans up the sky/framework/animation as follows: 1) I've moved code that's used only by the custom elements framework into sky/framework/elements/animation. This code is based on AnimationDelegates rather than Streams. 2) Rename ScrollCurve to ScrollBehavior because it encapsulates more behavior than just a curve. 3) Make the Generator interface explicit and mark subclasses as actual subclasses. 4) Move Simulation into generators.dart because it implements the Generator interface. 5) Move Animation out of generators.dart because it does not implement the Generator interface. R=eseidel@chromium.org Review URL: https://codereview.chromium.org/1001373002
167 lines
4.0 KiB
Plaintext
167 lines
4.0 KiB
Plaintext
<!--
|
|
// Copyright 2015 The Chromium Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
-->
|
|
<import src="shadow.sky" as="shadow" />
|
|
<import src="sky-element.sky" />
|
|
<import src="sky-scrollable.sky" />
|
|
|
|
<sky-element attributes="level:number">
|
|
<template>
|
|
<style>
|
|
#mask {
|
|
background-color: black;
|
|
will-change: opacity;
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
bottom: 0;
|
|
right: 0;
|
|
}
|
|
#content {
|
|
background-color: #FAFAFA;
|
|
will-change: transform;
|
|
position: absolute;
|
|
z-index: 2;
|
|
width: 256px;
|
|
top: 0;
|
|
left: 0;
|
|
bottom: 0;
|
|
}
|
|
</style>
|
|
<div id="mask" />
|
|
<div id="content">
|
|
<content/>
|
|
</div>
|
|
</template>
|
|
<script>
|
|
import "../animation/curves.dart";
|
|
import "../animation/timer.dart";
|
|
import "animation/controller.dart";
|
|
import "dart:math" as math;
|
|
import "dart:sky";
|
|
|
|
const double _kWidth = 256.0;
|
|
const double _kMinFlingVelocity = 0.4;
|
|
const double _kMinAnimationDurationMS = 246.0;
|
|
const double _kMaxAnimationDurationMS = 600.0;
|
|
const Cubic _kAnimationCurve = easeOut;
|
|
|
|
@Tagname('sky-drawer')
|
|
class SkyDrawer extends SkyElement implements AnimationDelegate {
|
|
Element _mask;
|
|
Element _content;
|
|
double _position = 0.0;
|
|
AnimationController _animation;
|
|
|
|
SkyDrawer() {
|
|
_animation = new AnimationController(this);
|
|
|
|
addEventListener('pointerdown', _handlePointerDown);
|
|
addEventListener('pointermove', _handlePointerMove);
|
|
addEventListener('pointerup', _handlePointerUp);
|
|
addEventListener('pointercancel', _handlePointerCancel);
|
|
}
|
|
|
|
void shadowRootReady() {
|
|
shadow.applyTo(shadowRoot);
|
|
_mask = shadowRoot.getElementById('mask');
|
|
_mask.addEventListener('gesturetap', _handleMaskTap);
|
|
_content = shadowRoot.getElementById('content');
|
|
_content.addEventListener('gestureflingstart', _handleFlingStart);
|
|
position = -_kWidth;
|
|
}
|
|
|
|
void toggle() {
|
|
if (isMostlyClosed)
|
|
open();
|
|
else
|
|
close();
|
|
}
|
|
|
|
void open() {
|
|
_animateToPosition(0.0);
|
|
}
|
|
|
|
void close() {
|
|
_animateToPosition(-_kWidth);
|
|
}
|
|
|
|
bool get isClosed => _position <= -_kWidth;
|
|
bool get isMostlyClosed => _position <= -_kWidth / 2;
|
|
double get position => _position;
|
|
|
|
set position(double value) {
|
|
double newPosition = math.min(0.0, math.max(value, -_kWidth));
|
|
_position = newPosition;
|
|
_content.style['transform'] = 'translateX(${newPosition}px)';
|
|
_mask.style['opacity'] = '${(newPosition / _kWidth + 1) * 0.25}';
|
|
style['display'] = isClosed ? 'none' : '';
|
|
}
|
|
|
|
void _settle() {
|
|
if (isMostlyClosed)
|
|
close();
|
|
else
|
|
open();
|
|
}
|
|
|
|
void _animateToPosition(double targetPosition) {
|
|
double currentPosition = _position;
|
|
double distance = (targetPosition - currentPosition).abs();
|
|
double duration = _kMaxAnimationDurationMS * distance / _kWidth;
|
|
_animation.start(
|
|
begin: currentPosition,
|
|
end: targetPosition,
|
|
duration: math.max(_kMinAnimationDurationMS, duration),
|
|
curve: _kAnimationCurve);
|
|
}
|
|
|
|
void updateAnimation(double p) {
|
|
position = p;
|
|
}
|
|
|
|
void _handleMaskTap(_) {
|
|
close();
|
|
}
|
|
|
|
void _handlePointerDown(_) {
|
|
_animation.stop();
|
|
}
|
|
|
|
void _handlePointerMove(PointerEvent event) {
|
|
position += event.dx;
|
|
}
|
|
|
|
void _handlePointerUp(_) {
|
|
if (!_animation.isAnimating)
|
|
_settle();
|
|
}
|
|
|
|
void _handlePointerCancel(_) {
|
|
if (!_animation.isAnimating)
|
|
_settle();
|
|
}
|
|
|
|
void _handleFlingStart(event) {
|
|
double direction = event.velocityX.sign;
|
|
double velocityX = event.velocityX.abs() / 1000;
|
|
if (velocityX < _kMinFlingVelocity)
|
|
return;
|
|
double targetPosition = direction < 0.0 ? -kWidth : 0.0;
|
|
double currentPosition = _position;
|
|
double distance = (targetPosition - currentPosition).abs();
|
|
double duration = distance / velocityX;
|
|
_animation.start(
|
|
begin: currentPosition,
|
|
end: targetPosition,
|
|
duration: duration,
|
|
curve: linear);
|
|
}
|
|
}
|
|
|
|
_init(script) => register(script, SkyDrawer);
|
|
</script>
|
|
</sky-element>
|