Unverified Commit 62674cee authored by Justin McCandless's avatar Justin McCandless Committed by GitHub

Interactive size const (#36964)

(Breaking Change) Move some hardcoded pixel values to reusable constants.
parent 9ae76255
......@@ -5,6 +5,7 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
import 'constants.dart';
import 'theme.dart';
const Color _kDisabledBackground = Color(0xFFA9A9A9);
......@@ -33,7 +34,7 @@ class CupertinoButton extends StatefulWidget {
this.padding,
this.color,
this.disabledColor,
this.minSize = 44.0,
this.minSize = kMinInteractiveDimensionCupertino,
this.pressedOpacity = 0.1,
this.borderRadius = const BorderRadius.all(Radius.circular(8.0)),
@required this.onPressed,
......@@ -52,7 +53,7 @@ class CupertinoButton extends StatefulWidget {
@required this.child,
this.padding,
this.disabledColor,
this.minSize = 44.0,
this.minSize = kMinInteractiveDimensionCupertino,
this.pressedOpacity = 0.1,
this.borderRadius = const BorderRadius.all(Radius.circular(8.0)),
@required this.onPressed,
......@@ -94,12 +95,8 @@ class CupertinoButton extends StatefulWidget {
/// Minimum size of the button.
///
/// Defaults to 44.0 which the iOS Human Interface Guideline recommends as the
/// minimum tappable area
///
/// See also:
///
/// * <https://developer.apple.com/ios/human-interface-guidelines/visual-design/adaptivity-and-layout/>
/// Defaults to kMinInteractiveDimensionCupertino which the iOS Human
/// Interface Guidelines recommends as the minimum tappable area.
final double minSize;
/// The opacity that the button will fade to when it is pressed.
......
// Copyright 2019 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.
/// The minimum dimension of any interactive region according to the iOS Human
/// Interface Guidelines.
///
/// This is used to avoid small regions that are hard for the user to interact
/// with. It applies to both dimensions of a region, so a square of size
/// kMinInteractiveDimension x kMinInteractiveDimension is the smallest
/// acceptable region that should respond to gestures.
///
/// See also:
///
/// * [kMinInteractiveDimension]
/// * <https://developer.apple.com/ios/human-interface-guidelines/visual-design/adaptivity-and-layout/>
const double kMinInteractiveDimensionCupertino = 44.0;
......@@ -11,6 +11,7 @@ import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'button.dart';
import 'constants.dart';
import 'icons.dart';
import 'page_scaffold.dart';
import 'route.dart';
......@@ -19,7 +20,7 @@ import 'theme.dart';
/// Standard iOS navigation bar height without the status bar.
///
/// This height is constant and independent of accessibility as it is in iOS.
const double _kNavBarPersistentHeight = 44.0;
const double _kNavBarPersistentHeight = kMinInteractiveDimensionCupertino;
/// Size increase from expanding the navigation bar into an iOS-11-style large title
/// form in a [CustomScrollView].
......
......@@ -11,6 +11,7 @@ import 'package:flutter/widgets.dart';
import 'chip_theme.dart';
import 'colors.dart';
import 'constants.dart';
import 'debug.dart';
import 'icons.dart';
import 'ink_well.dart';
......@@ -1731,7 +1732,7 @@ class _RawChipState extends State<RawChip> with TickerProviderStateMixin<RawChip
BoxConstraints constraints;
switch (widget.materialTapTargetSize ?? theme.materialTapTargetSize) {
case MaterialTapTargetSize.padded:
constraints = const BoxConstraints(minHeight: 48.0);
constraints = const BoxConstraints(minHeight: kMinInteractiveDimension);
break;
case MaterialTapTargetSize.shrinkWrap:
constraints = const BoxConstraints();
......
......@@ -4,6 +4,20 @@
import 'package:flutter/painting.dart';
/// The minimum dimension of any interactive region according to Material
/// guidelines.
///
/// This is used to avoid small regions that are hard for the user to interact
/// with. It applies to both dimensions of a region, so a square of size
/// kMinInteractiveDimension x kMinInteractiveDimension is the smallest
/// acceptable region that should respond to gestures.
///
/// See also:
///
/// * [kMinInteractiveDimensionCupertino]
/// * The Material spec on touch targets at <https://material.io/design/usability/accessibility.html#layout-typography>.
const double kMinInteractiveDimension = 48.0;
/// The height of the toolbar component of the [AppBar].
const double kToolbarHeight = 56.0;
......@@ -11,7 +25,7 @@ const double kToolbarHeight = 56.0;
const double kBottomNavigationBarHeight = 56.0;
/// The height of a tab bar containing text.
const double kTextTabBarHeight = 48.0;
const double kTextTabBarHeight = kMinInteractiveDimension;
/// The amount of time theme change animations should last.
const Duration kThemeChangeDuration = Duration(milliseconds: 200);
......
......@@ -10,6 +10,7 @@ import 'package:flutter/widgets.dart';
import 'checkbox.dart';
import 'colors.dart';
import 'constants.dart';
import 'debug.dart';
import 'divider.dart';
import 'dropdown.dart';
......@@ -262,7 +263,7 @@ class DataTable extends StatelessWidget {
this.sortColumnIndex,
this.sortAscending = true,
this.onSelectAll,
this.dataRowHeight = 48.0,
this.dataRowHeight = kMinInteractiveDimension,
this.headingRowHeight = 56.0,
this.horizontalMargin = 24.0,
this.columnSpacing = 56.0,
......@@ -321,7 +322,8 @@ class DataTable extends StatelessWidget {
/// The height of each row (excluding the row that contains column headings).
///
/// This value defaults to 48.0 to adhere to the Material Design specifications.
/// This value defaults to kMinInteractiveDimension to adhere to the Material
/// Design specifications.
final double dataRowHeight;
/// The height of the heading row.
......
......@@ -20,7 +20,7 @@ import 'shadows.dart';
import 'theme.dart';
const Duration _kDropdownMenuDuration = Duration(milliseconds: 300);
const double _kMenuItemHeight = 48.0;
const double _kMenuItemHeight = kMinInteractiveDimension;
const double _kDenseButtonHeight = 24.0;
const EdgeInsets _kMenuItemPadding = EdgeInsets.symmetric(horizontal: 16.0);
const EdgeInsetsGeometry _kAlignedButtonPadding = EdgeInsetsDirectional.only(start: 16.0, end: 4.0);
......
......@@ -5,13 +5,14 @@
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
import 'constants.dart';
import 'expand_icon.dart';
import 'ink_well.dart';
import 'material_localizations.dart';
import 'mergeable_material.dart';
import 'theme.dart';
const double _kPanelHeaderCollapsedHeight = 48.0;
const double _kPanelHeaderCollapsedHeight = kMinInteractiveDimension;
const double _kPanelHeaderExpandedHeight = 64.0;
class _SaltedKey<S, V> extends LocalKey {
......
......@@ -7,6 +7,7 @@ import 'dart:math' as math;
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
import 'constants.dart';
import 'debug.dart';
import 'icons.dart';
import 'ink_well.dart';
......@@ -15,8 +16,8 @@ import 'theme.dart';
import 'tooltip.dart';
// Minimum logical pixel size of the IconButton.
// See: <https://material.io/guidelines/layout/metrics-keylines.html#metrics-keylines-touch-target-size>
const double _kMinButtonSize = 48.0;
// See: <https://material.io/design/usability/accessibility.html#layout-typography>.
const double _kMinButtonSize = kMinInteractiveDimension;
/// A material design icon button.
///
......@@ -31,9 +32,9 @@ const double _kMinButtonSize = 48.0;
///
/// Requires one of its ancestors to be a [Material] widget.
///
/// The hit region of an icon button will, if possible, be at least 48.0 pixels
/// in size, regardless of the actual [iconSize], to satisfy the [touch target
/// size](https://material.io/guidelines/layout/metrics-keylines.html#metrics-keylines-touch-target-size)
/// The hit region of an icon button will, if possible, be at least
/// kMinInteractiveDimension pixels in size, regardless of the actual
/// [iconSize], to satisfy the [touch target size](https://material.io/guidelines/layout/metrics-keylines.html#metrics-keylines-touch-target-size)
/// requirements in the Material Design specification. The [alignment] controls
/// how the icon itself is positioned within the hit region.
///
......
......@@ -11,6 +11,7 @@ import 'package:flutter/gestures.dart' show DragStartBehavior;
import 'button_bar.dart';
import 'button_theme.dart';
import 'card.dart';
import 'constants.dart';
import 'data_table.dart';
import 'data_table_source.dart';
import 'debug.dart';
......@@ -70,7 +71,7 @@ class PaginatedDataTable extends StatefulWidget {
this.sortColumnIndex,
this.sortAscending = true,
this.onSelectAll,
this.dataRowHeight = 48.0,
this.dataRowHeight = kMinInteractiveDimension,
this.headingRowHeight = 56.0,
this.horizontalMargin = 24.0,
this.columnSpacing = 56.0,
......@@ -141,7 +142,8 @@ class PaginatedDataTable extends StatefulWidget {
/// The height of each row (excluding the row that contains column headings).
///
/// This value is optional and defaults to 48.0 if not specified.
/// This value is optional and defaults to kMinInteractiveDimension if not
/// specified.
final double dataRowHeight;
/// The height of the heading row.
......
......@@ -30,7 +30,7 @@ const Duration _kMenuDuration = Duration(milliseconds: 300);
const double _kBaselineOffsetFromBottom = 20.0;
const double _kMenuCloseIntervalEnd = 2.0 / 3.0;
const double _kMenuHorizontalPadding = 16.0;
const double _kMenuItemHeight = 48.0;
const double _kMenuItemHeight = kMinInteractiveDimension;
const double _kMenuDividerHeight = 16.0;
const double _kMenuMaxWidth = 5.0 * _kMenuWidthStep;
const double _kMenuMinWidth = 2.0 * _kMenuWidthStep;
......@@ -132,8 +132,8 @@ class _PopupMenuDividerState extends State<PopupMenuDivider> {
///
/// Typically the [child] of a [PopupMenuItem] is a [Text] widget. More
/// elaborate menus with icons can use a [ListTile]. By default, a
/// [PopupMenuItem] is 48 pixels high. If you use a widget with a different
/// height, it must be specified in the [height] property.
/// [PopupMenuItem] is kMinInteractiveDimension pixels high. If you use a widget
/// with a different height, it must be specified in the [height] property.
///
/// {@tool sample}
///
......@@ -189,7 +189,7 @@ class PopupMenuItem<T> extends PopupMenuEntry<T> {
/// The height of the entry.
///
/// Defaults to 48 pixels.
/// Defaults to kMinInteractiveDimension pixels.
@override
final double height;
......@@ -292,9 +292,10 @@ class PopupMenuItemState<T, W extends PopupMenuItem<T>> extends State<W> {
/// To show a popup menu, use the [showMenu] function. To create a button that
/// shows a popup menu, consider using [PopupMenuButton].
///
/// A [CheckedPopupMenuItem] is 48 pixels high, which matches the default height
/// of a [PopupMenuItem]. The horizontal layout uses a [ListTile]; the checkmark
/// is an [Icons.done] icon, shown in the [ListTile.leading] position.
/// A [CheckedPopupMenuItem] is kMinInteractiveDimension pixels high, which
/// matches the default height of a [PopupMenuItem]. The horizontal layout uses
/// a [ListTile]; the checkmark is an [Icons.done] icon, shown in the
/// [ListTile.leading] position.
///
/// {@tool sample}
///
......
......@@ -333,7 +333,7 @@ class RangeSlider extends StatefulWidget {
final RangeSemanticFormatterCallback semanticFormatterCallback;
// Touch width for the tap boundary of the slider thumbs.
static const double _minTouchTargetWidth = 48;
static const double _minTouchTargetWidth = kMinInteractiveDimension;
@override
_RangeSliderState createState() => _RangeSliderState();
......@@ -1387,4 +1387,4 @@ class _RenderRangeSlider extends RenderBox {
double _decreaseValue(double value) {
return (value - _semanticActionUnit).clamp(0.0, 1.0);
}
}
\ No newline at end of file
}
// Copyright 2019 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.
/// The minimum dimension of any interactive region according to the Material
/// guidelines.
///
/// This is used to avoid small regions that are hard for the user to interact
/// with. It applies to both dimensions of a region, so a square of size
/// kMinInteractiveDimension x kMinInteractiveDimension is the smallest
/// acceptable region that should respond to gestures.
///
/// See also:
///
/// * [kMinInteractiveDimensionCupertino]
const double kMinInteractiveDimension = 48.0;
......@@ -16,6 +16,7 @@ import 'package:flutter/gestures.dart' show DragStartBehavior;
import 'automatic_keep_alive.dart';
import 'basic.dart';
import 'binding.dart';
import 'constants.dart';
import 'debug.dart';
import 'focus_manager.dart';
import 'focus_scope.dart';
......@@ -1446,7 +1447,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
.getHandleSize(renderEditable.preferredLineHeight).height;
final double interactiveHandleHeight = math.max(
handleHeight,
kMinInteractiveSize,
kMinInteractiveDimension,
);
final Offset anchor = _selectionOverlay.selectionControls
.getHandleAnchor(
......
......@@ -12,6 +12,7 @@ import 'package:flutter/scheduler.dart';
import 'package:flutter/services.dart';
import 'basic.dart';
import 'constants.dart';
import 'container.dart';
import 'editable_text.dart';
import 'framework.dart';
......@@ -618,11 +619,6 @@ class _TextSelectionHandleOverlay extends StatefulWidget {
}
}
/// The minimum size that a widget should be in order to be easily interacted
/// with by the user.
@visibleForTesting
const double kMinInteractiveSize = 48.0;
class _TextSelectionHandleOverlayState
extends State<_TextSelectionHandleOverlay> with SingleTickerProviderStateMixin {
Offset _dragPosition;
......@@ -749,7 +745,7 @@ class _TextSelectionHandleOverlayState
// Make sure the GestureDetector is big enough to be easily interactive.
final Rect interactiveRect = handleRect.expandToInclude(
Rect.fromCircle(center: handleRect.center, radius: kMinInteractiveSize / 2),
Rect.fromCircle(center: handleRect.center, radius: kMinInteractiveDimension/ 2),
);
final RelativeRect padding = RelativeRect.fromLTRB(
math.max((interactiveRect.width - handleRect.width) / 2, 0),
......
......@@ -2268,8 +2268,8 @@ void main() {
expect(
pos,
inExclusiveRange(
0 - kMinInteractiveSize,
0 + kMinInteractiveSize,
0 - kMinInteractiveDimension,
0 + kMinInteractiveDimension,
),
);
break;
......@@ -2277,8 +2277,8 @@ void main() {
expect(
pos,
inExclusiveRange(
viewport.width - kMinInteractiveSize,
viewport.width + kMinInteractiveSize,
viewport.width - kMinInteractiveDimension,
viewport.width + kMinInteractiveDimension,
),
);
break;
......@@ -2286,8 +2286,8 @@ void main() {
expect(
pos,
inExclusiveRange(
0 - kMinInteractiveSize,
viewport.width + kMinInteractiveSize,
0 - kMinInteractiveDimension,
viewport.width + kMinInteractiveDimension,
),
);
break;
......@@ -2381,15 +2381,15 @@ void main() {
expect(
handles[0].localToGlobal(Offset.zero).dx,
inExclusiveRange(
-kMinInteractiveSize,
kMinInteractiveSize,
-kMinInteractiveDimension,
kMinInteractiveDimension,
),
);
expect(
handles[1].localToGlobal(Offset.zero).dx,
inExclusiveRange(
70.0 - kMinInteractiveSize,
70.0 + kMinInteractiveSize,
70.0 - kMinInteractiveDimension,
70.0 + kMinInteractiveDimension,
),
);
expect(state.selectionOverlay.handlesAreVisible, isTrue);
......@@ -2497,8 +2497,8 @@ void main() {
expect(
pos,
inExclusiveRange(
0 - kMinInteractiveSize,
0 + kMinInteractiveSize,
0 - kMinInteractiveDimension,
0 + kMinInteractiveDimension,
),
);
break;
......@@ -2506,8 +2506,8 @@ void main() {
expect(
pos,
inExclusiveRange(
viewport.width - kMinInteractiveSize,
viewport.width + kMinInteractiveSize,
viewport.width - kMinInteractiveDimension,
viewport.width + kMinInteractiveDimension,
),
);
break;
......@@ -2515,8 +2515,8 @@ void main() {
expect(
pos,
inExclusiveRange(
0 - kMinInteractiveSize,
viewport.width + kMinInteractiveSize,
0 - kMinInteractiveDimension,
viewport.width + kMinInteractiveDimension,
),
);
break;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment