mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00

Applies horizontal safe area insets to the animation demo in the Gallery. Specifically, this ensures the back button is positioned consistently with iOS expectations and that that main image card in the detail view respects safe area insets. This is to support the iPhone X sensor housing notch and other similarly creative display features when in landscape orientation.
161 lines
4.4 KiB
Dart
161 lines
4.4 KiB
Dart
// Copyright 2017 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 'package:flutter/foundation.dart';
|
|
import 'package:flutter/material.dart';
|
|
|
|
import 'sections.dart';
|
|
|
|
const double kSectionIndicatorWidth = 32.0;
|
|
|
|
// The card for a single section. Displays the section's gradient and background image.
|
|
class SectionCard extends StatelessWidget {
|
|
const SectionCard({ Key key, @required this.section })
|
|
: assert(section != null),
|
|
super(key: key);
|
|
|
|
final Section section;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return new DecoratedBox(
|
|
decoration: new BoxDecoration(
|
|
gradient: new LinearGradient(
|
|
begin: Alignment.centerLeft,
|
|
end: Alignment.centerRight,
|
|
colors: <Color>[
|
|
section.leftColor,
|
|
section.rightColor,
|
|
],
|
|
),
|
|
),
|
|
child: new Image.asset(
|
|
section.backgroundAsset,
|
|
package: section.backgroundAssetPackage,
|
|
color: const Color.fromRGBO(255, 255, 255, 0.075),
|
|
colorBlendMode: BlendMode.modulate,
|
|
fit: BoxFit.cover,
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
// The title is rendered with two overlapping text widgets that are vertically
|
|
// offset a little. It's supposed to look sort-of 3D.
|
|
class SectionTitle extends StatelessWidget {
|
|
static const TextStyle sectionTitleStyle = const TextStyle(
|
|
fontFamily: 'Raleway',
|
|
inherit: false,
|
|
fontSize: 24.0,
|
|
fontWeight: FontWeight.w500,
|
|
color: Colors.white,
|
|
textBaseline: TextBaseline.alphabetic,
|
|
);
|
|
|
|
static final TextStyle sectionTitleShadowStyle = sectionTitleStyle.copyWith(
|
|
color: const Color(0x19000000),
|
|
);
|
|
|
|
const SectionTitle({
|
|
Key key,
|
|
@required this.section,
|
|
@required this.scale,
|
|
@required this.opacity,
|
|
}) : assert(section != null),
|
|
assert(scale != null),
|
|
assert(opacity != null && opacity >= 0.0 && opacity <= 1.0),
|
|
super(key: key);
|
|
|
|
final Section section;
|
|
final double scale;
|
|
final double opacity;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return new IgnorePointer(
|
|
child: new Opacity(
|
|
opacity: opacity,
|
|
child: new Transform(
|
|
transform: new Matrix4.identity()..scale(scale),
|
|
alignment: Alignment.center,
|
|
child: new Stack(
|
|
children: <Widget>[
|
|
new Positioned(
|
|
top: 4.0,
|
|
child: new Text(section.title, style: sectionTitleShadowStyle),
|
|
),
|
|
new Text(section.title, style: sectionTitleStyle),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
// Small horizontal bar that indicates the selected section.
|
|
class SectionIndicator extends StatelessWidget {
|
|
const SectionIndicator({ Key key, this.opacity: 1.0 }) : super(key: key);
|
|
|
|
final double opacity;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return new IgnorePointer(
|
|
child: new Container(
|
|
width: kSectionIndicatorWidth,
|
|
height: 3.0,
|
|
color: Colors.white.withOpacity(opacity),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
// Display a single SectionDetail.
|
|
class SectionDetailView extends StatelessWidget {
|
|
SectionDetailView({ Key key, @required this.detail })
|
|
: assert(detail != null && detail.imageAsset != null),
|
|
assert((detail.imageAsset ?? detail.title) != null),
|
|
super(key: key);
|
|
|
|
final SectionDetail detail;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final Widget image = new DecoratedBox(
|
|
decoration: new BoxDecoration(
|
|
borderRadius: new BorderRadius.circular(6.0),
|
|
image: new DecorationImage(
|
|
image: new AssetImage(
|
|
detail.imageAsset,
|
|
package: detail.imageAssetPackage,
|
|
),
|
|
fit: BoxFit.cover,
|
|
alignment: Alignment.center,
|
|
),
|
|
),
|
|
);
|
|
|
|
Widget item;
|
|
if (detail.title == null && detail.subtitle == null) {
|
|
item = new Container(
|
|
height: 240.0,
|
|
padding: const EdgeInsets.all(16.0),
|
|
child: new SafeArea(top: false, bottom:false, child: image),
|
|
);
|
|
} else {
|
|
item = new ListTile(
|
|
title: new Text(detail.title),
|
|
subtitle: new Text(detail.subtitle),
|
|
leading: new SizedBox(width: 32.0, height: 32.0, child: image),
|
|
);
|
|
}
|
|
|
|
return new DecoratedBox(
|
|
decoration: new BoxDecoration(color: Colors.grey.shade200),
|
|
child: item,
|
|
);
|
|
}
|
|
}
|