Como tornar o aplicativo de vibração responsivo de acordo com diferentes tamanhos de tela?


92

Estou enfrentando dificuldades para torná-lo responsivo de acordo com vários tamanhos de tela. Como torná-lo responsivo?

@override
       Widget build(BuildContext context) {
       return new Container(
       decoration: new BoxDecoration(color: Colors.white),
       child: new Stack(
        children: [
          new Padding(
            padding: const EdgeInsets.only(bottom: 350.0),
            child: new GradientAppBar(" "),
          ),
          new Positioned(
            bottom: 150.0,
            height: 260.0,
            left: 10.0,
            right: 10.0,
            child: new Padding(
              padding: new EdgeInsets.all(10.0),
              child: new Card(
                child: new Column(
                  mainAxisSize: MainAxisSize.min,
                  children: <Widget>[
                    const ListTile(
                      title: const Text(
                        'LOGIN',
                        textAlign: TextAlign.center,
                        style: const TextStyle(
                          fontSize: 16.50,
                          fontFamily: "Helvetica",
                          fontWeight: FontWeight.bold,
                          color: Colors.black87,
                          letterSpacing: 1.00,
                        ),
                      ),
                    ),
                    new ListTile(
                      leading: const Icon(Icons.person),
                      title: new TextField(
                        controller: _user1,
                        decoration: new InputDecoration(
                            labelText: '     Enter a username'),
                      ),
                    ),
                    new ListTile(
                      leading: const Icon(Icons.person_pin),
                      title: new TextField(
                        controller: _pass1,
                        decoration: new InputDecoration(
                            labelText: '     Enter a password'),
                        obscureText: true,
                      ),
                    ),
                  ],
                ),
              ),
            ),
          ),
          new Positioned(
            bottom: 70.0,
            left: 15.0,
            right: 05.0,
            child: new ButtonTheme.bar(
            // make buttons use the appropriate styles for cards
              child: new ButtonBar(
                children: <Widget>[
                  new FlatButton(
                    padding: new EdgeInsets.only(right: 13.0),
                    child: new Text(
                      'REGISTER HERE',
                      style: new TextStyle(
                          color: Colors.black87,
                          fontFamily: "Helvetica",
                          fontSize: 15.00,
                          fontWeight: FontWeight.bold),
                    ),
                    onPressed: () {
                      Navigator.of(context).pushNamed('/facebook');
                    },
                  ),
                  new FlatButton(
                    padding: new EdgeInsets.only(right: 22.0),
                    child: new Text(
                      'FORGOT PASSWORD?',
                      style: new TextStyle(
                          color: Colors.black87,
                          fontFamily: "Helvetica",
                          fontSize: 15.00,
                          fontWeight: FontWeight.bold),
                    ),
                    onPressed: () {
                      Navigator.of(context).pushNamed('/Forgot');
                    },
                  ),
                ],
              ),
            ),
          ),
          new Positioned(
            bottom: 73.0,
            height: 180.0,
            left: 20.0,
            right: 52.0,
            child: new Padding(
              padding: new EdgeInsets.all(0.00),
              child: new ButtonTheme(
                minWidth: 10.0,
                height: 20.0,
                padding: new EdgeInsets.only(right: 37.0),
                child: new ButtonBar(children: <Widget>[
                  new CupertinoButton(
                      borderRadius:
                          const BorderRadius.all(const Radius.circular(36.0)),
                      padding: new EdgeInsets.only(left: 70.0),
                      color: const Color(0xFF426DB7),
                      child: new Text(
                        "     LOGIN                            ",
                        style: new TextStyle(
                            color: Colors.white,
                            fontSize: 12.50,
                            fontFamily: "Handwriting",
                            fontWeight: FontWeight.w500,
                            letterSpacing: 0.00),
                      ),
                      onPressed: () {})
                ]),
              ),
            ),
          ),
        ],
      ),
    );
  }
}

Eu escrevi uma solução simples aqui jaycoding.tech/tutorials/guides/… pois não acho que MediaQueryseja suficiente. Você pode querer dar uma olhada.
NduJay

Respostas:


76

Usando a MediaQueryclasse:

MediaQueryData queryData;
queryData = MediaQuery.of(context);

MediaQuery : Estabelece uma subárvore na qual as consultas de mídia são resolvidas para os dados fornecidos.

MediaQueryData : informações sobre uma mídia (por exemplo, uma janela).

Para obter o Device Pixel Ratio:

queryData.devicePixelRatio

Para obter a largura e a altura da tela do dispositivo:

queryData.size.width
queryData.size.height

Para obter o fator de escala do texto:

queryData.textScaleFactor

Usando a AspectRatioclasse:

Do doc:

Um widget que tenta dimensionar a criança para uma proporção de aspecto específica.

O widget tenta primeiro a maior largura permitida pelas restrições de layout. A altura do widget é determinada pela aplicação da proporção de aspecto dada à largura, expressa como uma proporção da largura para a altura.

Por exemplo, uma proporção de largura: altura de 16: 9 teria um valor de 16,0 / 9,0. Se a largura máxima for infinita, a largura inicial será determinada aplicando a proporção da imagem à altura máxima.

Agora considere um segundo exemplo, desta vez com uma proporção de 2,0 e restrições de layout que exigem que a largura esteja entre 0,0 e 100,0 e a altura entre 0,0 e 100,0. Selecionaremos uma largura de 100,0 (a maior permitida) e uma altura de 50,0 (para corresponder à proporção).

//example
new Center(
 child: new AspectRatio(
  aspectRatio: 100 / 100,
  child: new Container(
    decoration: new BoxDecoration(
      shape: BoxShape.rectangle,
      color: Colors.orange,
      )
    ),
  ),
),

Você também pode usar :


3
Consigo obter a largura e a altura do dispositivo, como posso definir o tamanho do teste, preenchimento e margem queryData.
Farhana

33

Esta classe ajudará e então inicializará a classe com o método init.

import 'package:flutter/widgets.dart';

class SizeConfig {
  static MediaQueryData _mediaQueryData;
  static double screenWidth;
  static double screenHeight;
  static double blockSizeHorizontal;
  static double blockSizeVertical;
  static double _safeAreaHorizontal;
  static double _safeAreaVertical;
  static double safeBlockHorizontal;
  static double safeBlockVertical;

  void init(BuildContext context){
    _mediaQueryData = MediaQuery.of(context);
    screenWidth = _mediaQueryData.size.width;
    screenHeight = _mediaQueryData.size.height;
    blockSizeHorizontal = screenWidth/100;
    blockSizeVertical = screenHeight/100;
    _safeAreaHorizontal = _mediaQueryData.padding.left +
        _mediaQueryData.padding.right;
    _safeAreaVertical = _mediaQueryData.padding.top +
        _mediaQueryData.padding.bottom;
    safeBlockHorizontal = (screenWidth - _safeAreaHorizontal)/100;
    safeBlockVertical = (screenHeight - _safeAreaVertical)/100;
  }
}

então em sua dimensão de widgets faça isso

Widget build(BuildContext context) {
    SizeConfig().init(context);
    return Container(
    height: SizeConfig.safeBlockVertical * 10, //10 for example
    width: SizeConfig.safeBlockHorizontal * 10, //10 for example
    );}

Todos os créditos para este autor de postagem: https://medium.com/flutter-community/flutter-effectively-scale-ui-according-to-different-screen-sizes-2cb7c115ea0a


Como adicionar parte inferior EdgeInsets com esta classe SizeConfig?
Farwa

Acho que o preenchimento do contêiner funcionará. Experimente e diga-me para te ajudar !!

16

O que eu faço é pegar a largura e a altura da tela e calcular uma grade de 100 * 100 para posicionar e dimensionar as coisas e salvá-las como variáveis ​​estáticas que podem ser reutilizadas. Funciona muito bem na maioria dos casos. Como isso:

AppConfig.width = MediaQuery.of(context).size.width;
AppConfig.height = MediaQuery.of(context).size.height;
AppConfig.blockSize = AppConfig.width / 100;
AppConfig.blockSizeVertical = AppConfig.height / 100;

Então eu dimensiono tudo de acordo com estes valores, assim:

double elementWidth = AppConfig.blockSize * 10.0;   // 10% of the screen width

ou

double fontSize = AppConfig.blockSize * 1.2;

Às vezes, a área segura (entalhe etc.) mata um layout, então você também pode considerar isso:

AppConfig.safeAreaHorizontal = MediaQuery.of(context).padding.left +
    MediaQuery.of(context).padding.right;

double screenWidthWithoutSafeArea = AppConfig.width - AppConfig.safeAreaHorizontal;

Isso funcionou muito bem em alguns projetos recentes.


1
Como calcular fontSizes? É bom calcular com base na largura ou altura?
Harsh Bhavsar

Estou calculando com base na largura. Mas, para ser honesto, não experimentei com aplicativos que suportam os modos paisagem e retrato. Mas você ainda pode ser capaz de calculá-lo de forma diferente nas duas orientações.
datayeah

Como isso resolve exatamente o problema das diferenças de densidade da tela? Ao dizer que você divide a tela em 100 * 100 blocos de grade, você faz parecer que os blocos resultantes são todos do mesmo tamanho (ou seja, quadrados), mas não são. Se você tiver um dispositivo com o dobro do número de pixels verticalmente (altura da tela) do que horizontalmente (largura da tela), seus blocos resultantes serão retângulos em vez de quadrados - o que significa que seu código ainda produz o mesmo problema que você começou tentando resolver. Teste seu código em várias densidades de tela para provar isso. Portanto, esta não é realmente uma solução para mim.
SilSur

@SilSur, certifique-se de que os blocos não são do mesmo tamanho em nenhum dispositivo e densidade, mas é isso que o faz funcionar (na maioria dos casos). eu só tenho que decidir para cada widget que adiciono à tela se eu quero que sua posição e tamanho sejam calculados em relação à largura ou altura de um bloco - ou ambos. Usei esse método em aplicativos executados em qualquer iphone, ipad ou telefone / tablet Android sem correções específicas do dispositivo. paisagem e retrato. mas você está certo de que esse método ainda não resolve perfeitamente problemas complexos de IU. ainda estou procurando algo melhor para lidar com isso.
datayeah de

11

Verificar MediaQueryaula

Por exemplo, para saber o tamanho dos meios de comunicação atuais (por exemplo, a janela que contém seu aplicativo), você pode ler a MediaQueryData.sizepropriedade do MediaQueryDataretornado por MediaQuery.of: MediaQuery.of(context).size.

Portanto, você pode fazer o seguinte:

 new Container(
                      height: MediaQuery.of(context).size.height/2,
..            )

você quer dizer ao invés de posicionar use mediaQuery ??
Praveen Dp

Eu não entendo o que você está tentando fazer
aziza

usando preenchimento posicionado dentro da pilha. eu o ajustei para o tamanho da tela. agora para torná-lo responsivo, devo usar o mediaquery no lugar do quê ??
Praveen Dp

7

A maneira mais fácil de tornar a interface do usuário responsiva para tamanhos de tela diferentes é o plug-in Sizer . Captura de tela do Sizer

Faça UI responsiva em qualquer dispositivo de tamanho de tela e tablet. Verifique este plugin ⬇️
https://pub.dev/packages/sizer

.h  - for widget height
.w  - for widget width
.sp - for font size

Use .h, .w,.sp após o valor como este ⬇️

Exemplo:

Container(
  height: 10.0.h,  //10% of screen height
  width: 80.0.w,   //80% of screen width
  child: Text('Sizer', style: TextStyle(fontSize: 12.0.sp)),
);

Eu construí muitos aplicativos responsivos com este plugin.


2
a abordagem é ótima, vou tentar observar o comportamento e depois entrar em produção com ele, se me satisfizer.
Wambert Orion

2
Muito obrigado @urmish patel, é a maneira mais fácil de tornar os aplicativos responsivos.
Tarun Sharma de

5

Você pode obter uma porcentagem da largura ou altura como entrada para o tamanho da escala.

fontSize: MediaQuery.of(_ctxt).size.height * 0.065

Onde o multiplicador no final tem um valor que faz o texto parecer bom para o emulador ativo.

Abaixo está como eu configurei para que todas as dimensões em escala sejam centralizadas em um só lugar. Dessa forma, você pode ajustá-los de forma fácil e rápida e executar novamente com Hot Reload sem ter que procurar as Media.of()chamadas em todo o código.

  1. Crie o arquivo para armazenar todos os mapeamentos appScale.dart

    class AppScale {
      BuildContext _ctxt;
    
      AppScale(this._ctxt);
    
      double get labelDim => scaledWidth(.04);
      double get popupMenuButton => scaledHeight(.065); 

      double scaledWidth(double widthScale) {
        return MediaQuery.of(_ctxt).size.width * widthScale;
      }
    
      double scaledHeight(double heightScale) {
        return MediaQuery.of(_ctxt).size.height * heightScale;
      }
    }

  1. Em seguida, faça referência a isso onde quer que você precise do valor em escala

    AppScale _scale = AppScale(context);

    // ... 

    Widget label1 = Text(
      "Some Label",
      style: TextStyle(fontSize: _scale.labelDim),
    );

Graças às respostas neste post


4
Place dependency in pubspec.yaml

flutter_responsive_screen: ^1.0.0

Function hp = Screen(MediaQuery.of(context).size).hp;
Function wp = Screen(MediaQuery.of(context).size).wp;

Example :
return Container(height: hp(27),weight: wp(27));

4
Talvez uma explicação sobre o que está acontecendo seja ótimo na próxima vez que você postar uma "solução"? De qualquer forma, eu verifiquei o GitHub para essa dependência. É basicamente uma única classe (com 16 linhas de código) que pega os valores de largura e altura de entrada e os dimensiona com base na largura e altura da tela como uma porcentagem. É essencialmente igual à solução de @datayeah - a única diferença é que esta está bem embalada. Os mesmos problemas do datayeah se aplicam aqui - não é uma boa solução para o dimensionamento 1: 1 em dispositivos de densidade de tela variada. O problema de densidade da tela NÃO É RESOLVIDO com esta "solução".
SilSur de

4

Depois de muita pesquisa e testes, desenvolvi uma solução para um aplicativo que estou convertendo de Android / iOS para Flutter.

Com o Android e o iOS, usei um 'fator de escala' aplicado aos tamanhos de fonte básicos, renderizando os tamanhos de texto relativos ao tamanho da tela.

Este artigo foi muito útil: https://medium.com/flutter-community/flutter-effectively-scale-ui-according-to-different-screen-sizes-2cb7c115ea0a

Criei um StatelessWidget para obter os tamanhos das fontes dos estilos tipográficos do Material Design. Obter dimensões do dispositivo usando MediaQuery, calcular um fator de escala e, em seguida, redefinir os tamanhos de texto do Material Design. O widget pode ser usado para definir um tema personalizado do Material Design.

Emuladores usados:

  • Pixel C - Tablet de 9,94 "
  • Pixel 3 - telefone de 5,46 "
  • iPhone 11 Pro Max - telefone de 5,8 "

Com tamanhos de fonte padrão

Com tamanhos de fonte redimensionados

set_app_theme.dart (widget SetAppTheme)

import 'package:flutter/material.dart';
import 'dart:math';

class SetAppTheme extends StatelessWidget {

  final Widget child;

  SetAppTheme({this.child});

  @override
  Widget build(BuildContext context) {

    final _divisor = 400.0;

    final MediaQueryData _mediaQueryData = MediaQuery.of(context);

    final _screenWidth = _mediaQueryData.size.width;
    final _factorHorizontal = _screenWidth / _divisor;

    final _screenHeight = _mediaQueryData.size.height;
    final _factorVertical = _screenHeight / _divisor;

    final _textScalingFactor = min(_factorVertical, _factorHorizontal);

    final _safeAreaHorizontal = _mediaQueryData.padding.left + _mediaQueryData.padding.right;
    final _safeFactorHorizontal = (_screenWidth - _safeAreaHorizontal) / _divisor;

    final _safeAreaVertical = _mediaQueryData.padding.top + _mediaQueryData.padding.bottom;
    final _safeFactorVertical = (_screenHeight - _safeAreaVertical) / _divisor;

    final _safeAreaTextScalingFactor = min(_safeFactorHorizontal, _safeFactorHorizontal);

    print('Screen Scaling Values:' + '_screenWidth: $_screenWidth');
    print('Screen Scaling Values:' + '_factorHorizontal: $_factorHorizontal ');

    print('Screen Scaling Values:' + '_screenHeight: $_screenHeight');
    print('Screen Scaling Values:' + '_factorVertical: $_factorVertical ');

    print('_textScalingFactor: $_textScalingFactor ');

    print('Screen Scaling Values:' + '_safeAreaHorizontal: $_safeAreaHorizontal ');
    print('Screen Scaling Values:' + '_safeFactorHorizontal: $_safeFactorHorizontal ');

    print('Screen Scaling Values:' + '_safeAreaVertical: $_safeAreaVertical ');
    print('Screen Scaling Values:' + '_safeFactorVertical: $_safeFactorVertical ');

    print('_safeAreaTextScalingFactor: $_safeAreaTextScalingFactor ');

    print('Default Material Design Text Themes');
    print('display4: ${Theme.of(context).textTheme.display4}');
    print('display3: ${Theme.of(context).textTheme.display3}');
    print('display2: ${Theme.of(context).textTheme.display2}');
    print('display1: ${Theme.of(context).textTheme.display1}');
    print('headline: ${Theme.of(context).textTheme.headline}');
    print('title: ${Theme.of(context).textTheme.title}');
    print('subtitle: ${Theme.of(context).textTheme.subtitle}');
    print('body2: ${Theme.of(context).textTheme.body2}');
    print('body1: ${Theme.of(context).textTheme.body1}');
    print('caption: ${Theme.of(context).textTheme.caption}');
    print('button: ${Theme.of(context).textTheme.button}');

    TextScalingFactors _textScalingFactors = TextScalingFactors(
        display4ScaledSize: (Theme.of(context).textTheme.display4.fontSize * _safeAreaTextScalingFactor),
        display3ScaledSize: (Theme.of(context).textTheme.display3.fontSize * _safeAreaTextScalingFactor),
        display2ScaledSize: (Theme.of(context).textTheme.display2.fontSize * _safeAreaTextScalingFactor),
        display1ScaledSize: (Theme.of(context).textTheme.display1.fontSize * _safeAreaTextScalingFactor),
        headlineScaledSize: (Theme.of(context).textTheme.headline.fontSize * _safeAreaTextScalingFactor),
        titleScaledSize: (Theme.of(context).textTheme.title.fontSize * _safeAreaTextScalingFactor),
        subtitleScaledSize: (Theme.of(context).textTheme.subtitle.fontSize * _safeAreaTextScalingFactor),
        body2ScaledSize: (Theme.of(context).textTheme.body2.fontSize * _safeAreaTextScalingFactor),
        body1ScaledSize: (Theme.of(context).textTheme.body1.fontSize * _safeAreaTextScalingFactor),
        captionScaledSize: (Theme.of(context).textTheme.caption.fontSize * _safeAreaTextScalingFactor),
        buttonScaledSize: (Theme.of(context).textTheme.button.fontSize * _safeAreaTextScalingFactor));

    return Theme(
      child: child,
      data: _buildAppTheme(_textScalingFactors),
    );
  }
}

final ThemeData customTheme = ThemeData(
  primarySwatch: appColorSwatch,
  // fontFamily: x,
);

final MaterialColor appColorSwatch = MaterialColor(0xFF3787AD, appSwatchColors);

Map<int, Color> appSwatchColors =
{
  50  : Color(0xFFE3F5F8),
  100 : Color(0xFFB8E4ED),
  200 : Color(0xFF8DD3E3),
  300 : Color(0xFF6BC1D8),
  400 : Color(0xFF56B4D2),
  500 : Color(0xFF48A8CD),
  600 : Color(0xFF419ABF),
  700 : Color(0xFF3787AD),
  800 : Color(0xFF337799),
  900 : Color(0xFF285877),
};

_buildAppTheme (TextScalingFactors textScalingFactors) {

  return customTheme.copyWith(

    accentColor: appColorSwatch[300],
    buttonTheme: customTheme.buttonTheme.copyWith(buttonColor: Colors.grey[500],),
    cardColor: Colors.white,
    errorColor: Colors.red,
    inputDecorationTheme: InputDecorationTheme(border: OutlineInputBorder(),),
    primaryColor: appColorSwatch[700],
    primaryIconTheme: customTheme.iconTheme.copyWith(color: appColorSwatch),
    scaffoldBackgroundColor: Colors.grey[100],
    textSelectionColor: appColorSwatch[300],
    textTheme: _buildAppTextTheme(customTheme.textTheme, textScalingFactors),
    appBarTheme: customTheme.appBarTheme.copyWith(
        textTheme: _buildAppTextTheme(customTheme.textTheme, textScalingFactors)),

//    accentColorBrightness: ,
//    accentIconTheme: ,
//    accentTextTheme: ,
//    appBarTheme: ,
//    applyElevationOverlayColor: ,
//    backgroundColor: ,
//    bannerTheme: ,
//    bottomAppBarColor: ,
//    bottomAppBarTheme: ,
//    bottomSheetTheme: ,
//    brightness: ,
//    buttonBarTheme: ,
//    buttonColor: ,
//    canvasColor: ,
//    cardTheme: ,
//    chipTheme: ,
//    colorScheme: ,
//    cupertinoOverrideTheme: ,
//    cursorColor: ,
//    dialogBackgroundColor: ,
//    dialogTheme: ,
//    disabledColor: ,
//    dividerColor: ,
//    dividerTheme: ,
//    floatingActionButtonTheme: ,
//    focusColor: ,
//    highlightColor: ,
//    hintColor: ,
//    hoverColor: ,
//    iconTheme: ,
//    indicatorColor: ,
//    materialTapTargetSize: ,
//    pageTransitionsTheme: ,
//    platform: ,
//    popupMenuTheme: ,
//    primaryColorBrightness: ,
//    primaryColorDark: ,
//    primaryColorLight: ,
//    primaryTextTheme: ,
//    secondaryHeaderColor: ,
//    selectedRowColor: ,
//    sliderTheme: ,
//    snackBarTheme: ,
//    splashColor: ,
//    splashFactory: ,
//    tabBarTheme: ,
//    textSelectionHandleColor: ,
//    toggleableActiveColor: ,
//    toggleButtonsTheme: ,
//    tooltipTheme: ,
//    typography: ,
//    unselectedWidgetColor: ,
  );
}

class TextScalingFactors {

  final double display4ScaledSize;
  final double display3ScaledSize;
  final double display2ScaledSize;
  final double display1ScaledSize;
  final double headlineScaledSize;
  final double titleScaledSize;
  final double subtitleScaledSize;
  final double body2ScaledSize;
  final double body1ScaledSize;
  final double captionScaledSize;
  final double buttonScaledSize;

  TextScalingFactors({

    @required this.display4ScaledSize,
    @required this.display3ScaledSize,
    @required this.display2ScaledSize,
    @required this.display1ScaledSize,
    @required this.headlineScaledSize,
    @required this.titleScaledSize,
    @required this.subtitleScaledSize,
    @required this.body2ScaledSize,
    @required this.body1ScaledSize,
    @required this.captionScaledSize,
    @required this.buttonScaledSize
  });
}

TextTheme _buildAppTextTheme(

    TextTheme _customTextTheme,
    TextScalingFactors _scaledText) {

  return _customTextTheme.copyWith(

    display4: _customTextTheme.display4.copyWith(fontSize: _scaledText.display4ScaledSize),
    display3: _customTextTheme.display3.copyWith(fontSize: _scaledText.display3ScaledSize),
    display2: _customTextTheme.display2.copyWith(fontSize: _scaledText.display2ScaledSize),
    display1: _customTextTheme.display1.copyWith(fontSize: _scaledText.display1ScaledSize),
    headline: _customTextTheme.headline.copyWith(fontSize: _scaledText.headlineScaledSize),
    title: _customTextTheme.title.copyWith(fontSize: _scaledText.titleScaledSize),
    subtitle: _customTextTheme.subtitle.copyWith(fontSize: _scaledText.subtitleScaledSize),
    body2: _customTextTheme.body2.copyWith(fontSize: _scaledText.body2ScaledSize),
    body1: _customTextTheme.body1.copyWith(fontSize: _scaledText.body1ScaledSize),
    caption: _customTextTheme.caption.copyWith(fontSize: _scaledText.captionScaledSize),
    button: _customTextTheme.button.copyWith(fontSize: _scaledText.buttonScaledSize),

  ).apply(bodyColor: Colors.black);
}

main.dart (aplicativo de demonstração)

import 'package:flutter/material.dart';
import 'package:scaling/set_app_theme.dart';


void main() => runApp(MyApp());


class MyApp extends StatelessWidget {

  @override
  Widget build(BuildContext context) {

    return MaterialApp(
      home: SetAppTheme(child: HomePage()),
    );
  }
}


class HomePage extends StatelessWidget {

  final demoText = '0123456789';

  @override
  Widget build(BuildContext context) {

    return SafeArea(
      child: Scaffold(
        appBar: AppBar(
          title: Text('Text Scaling with SetAppTheme',
            style: TextStyle(color: Colors.white),),
        ),
        body: SingleChildScrollView(
          child: Center(
            child: Padding(
              padding: const EdgeInsets.all(8.0),
              child: Column(
                children: <Widget>[
                  Text(
                    demoText,
                    style: TextStyle(
                      fontSize: Theme.of(context).textTheme.display4.fontSize,
                    ),
                  ),
                  Text(
                    demoText,
                    style: TextStyle(
                      fontSize: Theme.of(context).textTheme.display3.fontSize,
                    ),
                  ),
                  Text(
                    demoText,
                    style: TextStyle(
                      fontSize: Theme.of(context).textTheme.display2.fontSize,
                    ),
                  ),
                  Text(
                    demoText,
                    style: TextStyle(
                      fontSize: Theme.of(context).textTheme.display1.fontSize,
                    ),
                  ),
                  Text(
                    demoText,
                    style: TextStyle(
                      fontSize: Theme.of(context).textTheme.headline.fontSize,
                    ),
                  ),
                  Text(
                    demoText,
                    style: TextStyle(
                      fontSize: Theme.of(context).textTheme.title.fontSize,
                    ),
                  ),
                  Text(
                    demoText,
                    style: TextStyle(
                      fontSize: Theme.of(context).textTheme.subtitle.fontSize,
                    ),
                  ),
                  Text(
                    demoText,
                    style: TextStyle(
                      fontSize: Theme.of(context).textTheme.body2.fontSize,
                    ),
                  ),
                  Text(
                    demoText,
                    style: TextStyle(
                      fontSize: Theme.of(context).textTheme.body1.fontSize,
                    ),
                  ),
                  Text(
                    demoText,
                    style: TextStyle(
                      fontSize: Theme.of(context).textTheme.caption.fontSize,
                    ),
                  ),
                  Text(
                    demoText,
                    style: TextStyle(
                      fontSize: Theme.of(context).textTheme.button.fontSize,
                    ),
                  ),
                ],
              ),
            ),
          ),
        ),
      ),
    );
  }
}

3

Tenho criticado as soluções de outras pessoas (@datayeah & Vithani Ravi) um pouco difícil aqui, então pensei em compartilhar minhas próprias tentativas de resolver esse problema de dimensionamento de densidade de tela variável ou calar a boca. Portanto, abordo este problema a partir de uma base sólida / fixa: baseio todo o meu dimensionamento em uma proporção fixa (imutável) de 2: 1 (altura: largura). Eu tenho uma classe auxiliar "McGyver" que faz todo o trabalho pesado (e ajuste de código útil) em meu aplicativo. Esta classe "McGyver" contém apenas métodos estáticos e membros da classe constante estática.

MÉTODO DE ESCALA DE RAZÃO: Eu dimensiono a largura e a altura independentemente com base na proporção de aspecto 2: 1. Eu pego os valores de entrada de largura e altura e divido cada um pelas constantes de largura e altura e, finalmente, calculo um fator de ajuste pelo qual escalono os respectivos valores de entrada de largura e altura. O código real é o seguinte:

import 'dart:math';
import 'package:flutter/material.dart';

class McGyver {

  static const double _fixedWidth = 410;    // Set to an Aspect Ratio of 2:1 (height:width)
  static const double _fixedHeight = 820;   // Set to an Aspect Ratio of 2:1 (height:width) 

  // Useful rounding method (@andyw solution -> /programming/28419255/how-do-you-round-a-double-in-dart-to-a-given-degree-of-precision-after-the-decim/53500405#53500405)
  static double roundToDecimals(double val, int decimalPlaces){
    double mod = pow(10.0, decimalPlaces);
    return ((val * mod).round().toDouble() / mod);
  }

  // The 'Ratio-Scaled' Widget method (takes any generic widget and returns a "Ratio-Scaled Widget" - "rsWidget")
  static Widget rsWidget(BuildContext ctx, Widget inWidget, double percWidth, double percHeight) {

    // ---------------------------------------------------------------------------------------------- //
    // INFO: Ratio-Scaled "SizedBox" Widget - Scaling based on device's height & width at 2:1 ratio.  //
    // ---------------------------------------------------------------------------------------------- //

    final int _decPlaces = 5;
    final double _fixedWidth = McGyver._fixedWidth;
    final double _fixedHeight = McGyver._fixedHeight;

    Size _scrnSize = MediaQuery.of(ctx).size;                // Extracts Device Screen Parameters.
    double _scrnWidth = _scrnSize.width.floorToDouble();     // Extracts Device Screen maximum width.
    double _scrnHeight = _scrnSize.height.floorToDouble();   // Extracts Device Screen maximum height.

    double _rsWidth = 0;
    if (_scrnWidth == _fixedWidth) {   // If input width matches fixedWidth then do normal scaling.
      _rsWidth = McGyver.roundToDecimals((_scrnWidth * (percWidth / 100)), _decPlaces);
    } else {   // If input width !match fixedWidth then do adjustment factor scaling.
      double _scaleRatioWidth = McGyver.roundToDecimals((_scrnWidth / _fixedWidth), _decPlaces);
      double _scalerWidth = ((percWidth + log(percWidth + 1)) * pow(1, _scaleRatioWidth)) / 100;
      _rsWidth = McGyver.roundToDecimals((_scrnWidth * _scalerWidth), _decPlaces);
    }

    double _rsHeight = 0;
    if (_scrnHeight == _fixedHeight) {   // If input height matches fixedHeight then do normal scaling.
      _rsHeight = McGyver.roundToDecimals((_scrnHeight * (percHeight / 100)), _decPlaces);
    } else {   // If input height !match fixedHeight then do adjustment factor scaling.
      double _scaleRatioHeight = McGyver.roundToDecimals((_scrnHeight / _fixedHeight), _decPlaces);
      double _scalerHeight = ((percHeight + log(percHeight + 1)) * pow(1, _scaleRatioHeight)) / 100;
      _rsHeight = McGyver.roundToDecimals((_scrnHeight * _scalerHeight), _decPlaces);
    }

    // Finally, hand over Ratio-Scaled "SizedBox" widget to method call.
    return SizedBox(
      width: _rsWidth,
      height: _rsHeight,
      child: inWidget,
    );
  }

}

... ... ...

Em seguida, você dimensionaria individualmente seus widgets (que para minha doença perfeccionista é TODA a minha IU) com uma chamada estática simples para o método "rsWidget ()" da seguinte maneira:

  // Step 1: Define your widget however you like (this widget will be supplied as the "inWidget" arg to the "rsWidget" method in Step 2)...
  Widget _btnLogin = RaisedButton(color: Colors.blue, elevation: 9.0, 
                                  shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(McGyver.rsDouble(context, ScaleType.width, 2.5))),
                                  child: McGyver.rsText(context, "LOGIN", percFontSize: EzdFonts.button2_5, textColor: Colors.white, fWeight: FontWeight.bold),
                                  onPressed: () { _onTapBtnLogin(_tecUsrId.text, _tecUsrPass.text); }, );

  // Step 2: Scale your widget by calling the static "rsWidget" method...
  McGyver.rsWidget(context, _btnLogin, 34.5, 10.0)   // ...and Bob's your uncle!!

O legal é que o método "rsWidget ()" retorna um widget !! Portanto, você pode atribuir o widget escalado a outra variável _rsBtnLoginpara usar em qualquer lugar - ou pode simplesmente usar a McGyver.rsWidget()chamada de método completa no local dentro de seubuild() método (exatamente como você precisa que seja posicionado na árvore do widget) e funcionará perfeitamente como deveria.

Para os codificadores mais astutos: você deve ter notado que usei dois métodos escalonados de proporção adicionais McGyver.rsText()e McGyver.rsDouble()(não definidos no código acima) no meu RaisedButton()- então, basicamente, enlouqueço com essas coisas de escalonamento ... porque exijo que meus aplicativos sejam absolutamente pixel perfeito em qualquer escala ou densidade de tela !! Eu dimensiono a proporção de meus ints, duplos, preenchimento, texto (tudo que requer consistência de IU entre dispositivos). Eu dimensiono meus textos apenas com base na largura, mas especifico qual eixo usar para todas as outras escalas (como foi feito com o ScaleType.widthenum usado para a McGyver.rsDouble()chamada no exemplo de código acima).

Eu sei que isso é uma loucura - e é muito trabalho a fazer no thread principal - mas eu espero que alguém veja minha tentativa aqui e me ajude a encontrar uma solução melhor (mais leve) para minha densidade de tela de escala 1: 1 pesadelos.


1
@ Abbas.M - Sim, fiz uma pequena alteração na linha de código de escala de proporção [veja o código atualizado] e acredito que seja o mais próximo que posso chegar de uma solução de escala de proporção de 1: 1 real - tentei vários de opções para obter este. Ainda existem alguns problemas de escala estranhos [casos extremos] com este código atualizado, mas a semelhança da interface do usuário em telas de densidade múltipla é realmente convincente - diferença muito sutil observável entre as telas com o código atualizado. Deixe-me saber o que você pensa - comentários são muito apreciados.
SilSur

a coisa óbvia sobre o thread principal, mova o init e as chamadas para o bloco principal do app init já que o tamanho da tela não mudará após o app init, então você só tem o thread principal atingido uma vez no app init em vez de, por exemplo, cada renderização do widget
Fred Grott

@SilSur, sua solução parece ótima. Você se importa em compartilhar toda a classe McGyver?
David,

@David - A classe McGyver é uma classe muito pesada (e específica do projeto). O que usei neste exemplo tem muitas funções que não são relevantes para o problema de dimensionamento da IU. Portanto, é exagero / ineficiente para mim fazer o upload de toda a classe. No entanto, melhorei um pouco a classe e postei uma versão diferente do código em outra pergunta do SO . Talvez você possa atualizar seu código de escala ao longo das linhas do código aprimorado na URL fornecida.
SilSur

1

Você pode usar MediaQuery para a dimensão do pai ou FractionallySizedBox como contêineres.


1

Minha abordagem do problema é semelhante à maneira como datayeah o fez. Eu tinha muitos valores codificados de largura e altura e o aplicativo parecia bom em um dispositivo específico. Peguei a altura da tela do dispositivo e acabei de criar um fator para dimensionar os valores codificados.

double heightFactor = MediaQuery.of(context).size.height/708

onde 708 é a altura do dispositivo específico.


1

Tento tornar isso o mais simples possível. experimente. Eu faço um utilitário responsivo tendo a função getresponsivevalue responsável por fornecer valor de acordo com o tamanho da tela se você não atribuir valor para uma tela média, tela grande, modo paisagem Por padrão, fornece um valor atribuído para tela curta. uma recepção calorosa para qualquer dúvida. Eu adoraria melhorar

class SampleView extends StatelessWidget {
@override
Widget build(BuildContext context) {
 return Center(
  child: Container(
    width: 200,
    height: 200,
    color: Responsive().getResponsiveValue(
        forLargeScreen: Colors.red,
        forMediumScreen: Colors.green,
        forShortScreen: Colors.yellow,
        forMobLandScapeMode: Colors.blue,
        context: context),
  ),
);

}}

 // utility class
          class Responsive {
            // function reponsible for providing value according to screensize
            getResponsiveValue(
                {dynamic forShortScreen,
                dynamic forMediumScreen,
                dynamic forLargeScreen,
                dynamic forMobLandScapeMode,
                BuildContext context}) {

              if (isLargeScreen(context)) {

                return forLargeScreen ?? forShortScreen;
              } else if (isMediumScreen(context)) {

                return forMediumScreen ?? forShortScreen;
              } 
           else if (isSmallScreen(context) && isLandScapeMode(context)) {

                return forMobLandScapeMode ?? forShortScreen;
              } else {
                return forShortScreen;
              }
            }
          
            isLandScapeMode(BuildContext context) {
              if (MediaQuery.of(context).orientation == Orientation.landscape) {
                return true;
              } else {
                return false;
              }
            }
          
            static bool isLargeScreen(BuildContext context) {
              return getWidth(context) > 1200;
            }
          
            static bool isSmallScreen(BuildContext context) {
              return getWidth(context) < 800;
            }
          
            static bool isMediumScreen(BuildContext context) {
              return getWidth(context) > 800 && getWidth(context) < 1200;
            }
          
            static double getWidth(BuildContext context) {
              return MediaQuery.of(context).size.width;
            }
          }

0

confira esta página do flutter wiki:

Criação de aplicativos responsivos

Use a classe LayoutBuilder: de sua propriedade builder, você obtém um BoxConstraints. Examine as propriedades da restrição para decidir o que exibir. Por exemplo, se maxWidth for maior do que o ponto de interrupção de largura, retorne um objeto Scaffold com uma linha que possui uma lista à esquerda. Se for mais estreito, retorne um objeto Scaffold com uma gaveta contendo essa lista. Você também pode ajustar a tela com base na altura do dispositivo, na proporção da imagem ou em alguma outra propriedade. Quando as restrições mudam (por exemplo, o usuário gira o telefone ou coloca seu aplicativo em uma IU de bloco no Nougat), a função de construção será executada novamente.


0

crie o nome do arquivo (app_config.dart) no nome da pasta (responsive_screen) na pasta lib:

import 'package:flutter/material.dart';

class AppConfig {
  BuildContext _context;
  double _height;
  double _width;
  double _heightPadding;
  double _widthPadding;

  AppConfig(this._context) {
    MediaQueryData _queryData = MediaQuery.of(_context);
    _height = _queryData.size.height / 100.0;
    _width = _queryData.size.width / 100.0;
    _heightPadding =
    _height - ((_queryData.padding.top + _queryData.padding.bottom) / 100.0);
    _widthPadding =
      _width - (_queryData.padding.left + _queryData.padding.right) / 100.0;
  }

  double rH(double v) {
   return _height * v;
  }

  double rW(double v) {
    return _width * v;
  }

  double rHP(double v) {
    return _heightPadding * v;
  }

 double rWP(double v) {
   return _widthPadding * v;
 }
}

então:

import 'responsive_screen/app_config.dart';
 ...
class RandomWordsState extends State<RandomWords> {
  AppConfig _ac;
  ...
  @override
  Widget build(BuildContext context) {
    _ac = AppConfig(context);
    ...
    return Scaffold(
      body: Container(
        height: _ac.rHP(50),
        width: _ac.rWP(50),
        color: Colors.red,
        child: Text('Test'),
      ),
    );
    ...
  }

0

Este problema pode ser resolvido usando MediaQuery.of (contexto)

Para obter a largura da tela: MediaQuery.of(context).size.width

Para obter a altura da tela: MediaQuery.of(context).size.height

Para obter mais informações sobre o MediaQuery Widget watch, https://www.youtube.com/watch?v=A3WrA4zAaPw


0
  padding: EdgeInsets.only(
      left: 4.0,
      right: ResponsiveWidget.isSmallScreen(context) ? 4: 74, //Check for screen type
      top: 10,
      bottom: 40),

Isso é bom por recomendação do Google, mas pode não ser perfeito.


0

ResponsiveBuilder usado ou ScreenTypeLayout

import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:responsive_builder/responsive_builder.dart';

class Sample extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        elevation: 0,
        backgroundColor: Colors.black,
      ),
      body: ResponsiveBuilder(
        builder: (context, info) {
          var screenType = info.deviceScreenType;
          String _text;
          switch (screenType){
            case DeviceScreenType.desktop: {
              _text = 'Desktop';
              break;
            }
            case DeviceScreenType.tablet: {
              _text = 'Tablet';
              break;
            }
            case DeviceScreenType.mobile: {
              _text = 'Mobile';
              break;
            }
            case DeviceScreenType.watch: {
              _text = 'Watch';
              break;
            }
            default:
              return null;
          }
          return Center(child: Text(_text, style: TextStyle(fontSize: 32, color: Colors.black),));
        },
      ),
    );
  }
}

// screen type layout
ScreenTypeLayout.builder(
  mobile: MobilePage(),
  tablet: TabletPage(),
  desktop: DesktopPage(),
  watch: Watchpage(),
);


Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.