mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
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/controller.dart";
|
|
import "animation/curves.dart";
|
|
import "animation/timer.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>
|