mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
For some reason, the fling looks correct when we don't divide by the device pixel ratio when converting from mojo::Event to blink::WebInputEvent. Maybe the gesture detector is confused somehow about physical / logical pixels? R=eseidel@chromium.org, esprehn@chromium.org Review URL: https://codereview.chromium.org/885213002
163 lines
3.7 KiB
Plaintext
163 lines
3.7 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="animation/controller.sky" as="AnimationController" />
|
|
<import src="animation/curves.sky" as="Curves" />
|
|
<import src="sky-element/sky-element.sky" as="SkyElement" />
|
|
<import src="sky-scrollable.sky" />
|
|
|
|
<sky-element
|
|
name="sky-drawer"
|
|
on-pointerdown="handlePointerDown"
|
|
on-pointermove="handlePointerMove"
|
|
on-pointerup="handlePointerUp"
|
|
on-pointercancel="handlePointerCancel">
|
|
<template>
|
|
<style>
|
|
#mask {
|
|
background-color: black;
|
|
will-change: opacity;
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
bottom: 0;
|
|
right: 0;
|
|
}
|
|
#content {
|
|
background-color: yellow;
|
|
will-change: transform;
|
|
position: absolute;
|
|
width: 256px;
|
|
top: 0;
|
|
left: 0;
|
|
bottom: 0;
|
|
}
|
|
</style>
|
|
<div id="mask" on-click="handleMaskClick" />
|
|
<div id="content" on-gestureflingstart="handleFlingStart">
|
|
<content/>
|
|
</div>
|
|
</template>
|
|
<script>
|
|
const kWidth = 256;
|
|
const kMinFlingVelocity = 0.4;
|
|
const kMinAnimationDurationMS = 246;
|
|
const kMaxAnimationDurationMS = 600;
|
|
const kAnimationCurve = Curves.easeInOut;
|
|
|
|
module.exports = class extends SkyElement {
|
|
created() {
|
|
this.position_ = 0;
|
|
this.mask_ = null;
|
|
this.content_ = null;
|
|
this.animation_ = new AnimationController(this);
|
|
}
|
|
|
|
shadowRootReady() {
|
|
this.mask_ = this.shadowRoot.getElementById('mask');
|
|
this.content_ = this.shadowRoot.getElementById('content');
|
|
this.position = -kWidth;
|
|
}
|
|
|
|
toggle() {
|
|
if (this.isMostlyClosed)
|
|
this.open();
|
|
else
|
|
this.close();
|
|
}
|
|
|
|
open() {
|
|
this.animateToPosition_(0);
|
|
}
|
|
|
|
close() {
|
|
this.animateToPosition_(-kWidth);
|
|
}
|
|
|
|
get isClosed() {
|
|
return this.position_ <= -kWidth;
|
|
}
|
|
|
|
get isMostlyClosed() {
|
|
return this.position_ <= -kWidth / 2;
|
|
}
|
|
|
|
get position() {
|
|
return this.position_;
|
|
}
|
|
|
|
set position(value) {
|
|
var newPosition = Math.min(0, Math.max(value, -kWidth));
|
|
this.position_ = newPosition;
|
|
this.content_.style.transform = 'translateX(' + newPosition + 'px)';
|
|
this.mask_.style.opacity = (newPosition / kWidth + 1) * 0.25;
|
|
this.style.display = this.isClosed ? 'none' : '';
|
|
}
|
|
|
|
settle_() {
|
|
if (this.isMostlyClosed)
|
|
this.close();
|
|
else
|
|
this.open();
|
|
}
|
|
|
|
animateToPosition_(targetPosition) {
|
|
var currentPosition = this.position_;
|
|
var distance = Math.abs(targetPosition - currentPosition);
|
|
var duration = kMaxAnimationDurationMS * distance / kWidth;
|
|
this.animation_.start({
|
|
begin: currentPosition,
|
|
end: targetPosition,
|
|
duration: Math.max(kMinAnimationDurationMS, duration),
|
|
curve: kAnimationCurve,
|
|
});
|
|
}
|
|
|
|
updateAnimation(position) {
|
|
this.position = position;
|
|
}
|
|
|
|
handleMaskClick() {
|
|
this.close();
|
|
}
|
|
|
|
handlePointerDown(event) {
|
|
this.animation_.stop();
|
|
}
|
|
|
|
handlePointerMove(event) {
|
|
this.position += event.dx;
|
|
}
|
|
|
|
handlePointerUp(event) {
|
|
if (!this.animation_.isAnimating)
|
|
this.settle_();
|
|
}
|
|
|
|
handlePointerCancel(event) {
|
|
if (!this.animation_.isAnimating)
|
|
this.settle_();
|
|
}
|
|
|
|
handleFlingStart(event) {
|
|
var direction = Math.sign(event.velocityX);
|
|
var velocityX = Math.abs(event.velocityX) / 1000;
|
|
if (velocityX < kMinFlingVelocity)
|
|
return;
|
|
var targetPosition = direction < 0 ? -kWidth : 0;
|
|
var currentPosition = this.position_;
|
|
var distance = Math.abs(targetPosition - currentPosition);
|
|
var duration = distance / velocityX;
|
|
this.animation_.start({
|
|
begin: currentPosition,
|
|
end: targetPosition,
|
|
duration: duration,
|
|
curve: Curves.linear,
|
|
});
|
|
}
|
|
}.register();
|
|
</script>
|
|
</sky-element>
|