Làm thế nào để làm cho ứng dụng rung động đáp ứng theo kích thước màn hình khác nhau?


84

Tôi đang gặp khó khăn để làm cho nó phản hồi theo các kích thước màn hình khác nhau. Làm thế nào để làm cho nó phản hồi?

@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: () {})
                ]),
              ),
            ),
          ),
        ],
      ),
    );
  }
}

Câu trả lời:


71

Sử dụng MediaQuerylớp:

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

MediaQuery : Thiết lập một cây con trong đó các truy vấn phương tiện giải quyết cho dữ liệu nhất định.

MediaQueryData : Thông tin về một phần của phương tiện (ví dụ: cửa sổ).

Để có được Tỷ lệ pixel thiết bị:

queryData.devicePixelRatio

Để có chiều rộng và chiều cao của màn hình thiết bị:

queryData.size.width
queryData.size.height

Để nhận hệ số tỷ lệ văn bản:

queryData.textScaleFactor

Sử dụng AspectRatiolớp:

Từ tài liệu:

Một tiện ích cố gắng định kích thước con theo một tỷ lệ khung hình cụ thể.

Trước tiên, tiện ích con sẽ thử chiều rộng lớn nhất được phép bởi các ràng buộc bố cục. Chiều cao của tiện ích con được xác định bằng cách áp dụng tỷ lệ co đã cho cho chiều rộng, được biểu thị bằng tỷ lệ chiều rộng so với chiều cao.

Ví dụ: tỷ lệ co 16: 9 width: height sẽ có giá trị là 16.0 / 9.0. Nếu chiều rộng tối đa là vô hạn, chiều rộng ban đầu được xác định bằng cách áp dụng tỷ lệ co cho chiều cao tối đa.

Bây giờ hãy xem xét một ví dụ thứ hai, lần này với tỷ lệ khung hình là 2,0 và các ràng buộc về bố cục yêu cầu chiều rộng phải từ 0,0 đến 100,0 và chiều cao phải từ 0,0 đến 100,0. Chúng tôi sẽ chọn chiều rộng 100,0 (lớn nhất được phép) và chiều cao 50,0 (để khớp với tỷ lệ khung hình).

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

Ngoài ra bạn có thể sử dụng :


3
Tôi có thể lấy chiều rộng và chiều cao của thiết bị, làm cách nào tôi có thể đặt kích thước thử nghiệm, phần đệm, lề qua queryData.
Farhana

28

Lớp này sẽ trợ giúp và sau đó khởi tạo lớp bằng phương thức 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;
  }
}

thì trong thứ nguyên widget của bạn, hãy làm điều này

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

Tất cả các khoản tín dụng cho tác giả bài đăng này: https://medium.com/flutter-community/flutter-effaries-scale-ui-according-to-dierence-screen-sizes-2cb7c115ea0a


Làm thế nào để thêm EdgeInsets dưới cùng với lớp SizeConfig này?
Farwa

Tôi nghĩ như một lớp đệm của thùng chứa sẽ hoạt động. Hãy thử và nói để tôi giúp bạn !!

16

Những gì tôi làm là lấy chiều rộng và chiều cao của màn hình và tính toán lưới 100 * 100 để định vị và chia tỷ lệ mọi thứ và lưu nó dưới dạng các biến tĩnh có thể được sử dụng lại. Hoạt động khá tốt trong hầu hết các trường hợp. Như thế này:

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

Sau đó, tôi chia tỷ lệ mọi thứ theo các giá trị này, như thế này:

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

hoặc là

double fontSize = AppConfig.blockSize * 1.2;

Đôi khi vùng an toàn (rãnh, v.v.) giết chết một bố cục, vì vậy bạn cũng có thể xem xét điều này:

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

double screenWidthWithoutSafeArea = AppConfig.width - AppConfig.safeAreaHorizontal;

Điều này đã hoạt động tốt trên một số dự án gần đây.


1
Làm thế nào để tính toán kích thước phông chữ? Nó là tốt để tính toán dựa trên chiều rộng hoặc chiều cao?
Harsh Bhavsar

Tôi đang tính toán chúng dựa trên chiều rộng. Nhưng thành thật mà nói, tôi đã không thử nó với các ứng dụng hỗ trợ cả hai, chế độ ngang và dọc. Nhưng bạn vẫn có thể tính toán nó khác nhau trên cả hai hướng.
datayeah

Làm thế nào để giải quyết vấn đề chênh lệch mật độ màn hình một cách chính xác? Bằng cách nói rằng bạn chia màn hình thành các khối lưới 100 * 100, bạn làm cho nó giống như các khối kết quả đều có kích thước bằng nhau (tức là hình vuông), nhưng chúng không phải vậy. Nếu bạn có một thiết bị có gấp đôi số pixel theo chiều dọc (chiều cao màn hình) so với chiều ngang (chiều rộng màn hình) thì khối kết quả của bạn sẽ là hình chữ nhật thay vì hình vuông - có nghĩa là mã của bạn vẫn tạo ra cùng một vấn đề mà bạn đã bắt đầu cố gắng giải quyết. Kiểm tra mã của bạn trên nhiều mật độ màn hình để chứng minh điều này. Vì vậy, đây không thực sự là một giải pháp cho tôi.
SilSur,

@SilSur, hãy chắc chắn rằng các khối không có cùng kích thước trên bất kỳ thiết bị và mật độ nào, nhưng đó là điều khiến nó hoạt động (trong hầu hết các trường hợp). tôi chỉ phải quyết định cho mỗi tiện ích tôi thêm vào màn hình nếu tôi muốn vị trí và kích thước của nó được tính toán liên quan đến chiều rộng hoặc chiều cao của khối - hoặc cả hai. tôi đã sử dụng phương pháp này trong các ứng dụng chạy trên bất kỳ điện thoại / máy tính bảng iphone, ipad hoặc android nào mà không cần chỉnh sửa theo thiết bị cụ thể. phong cảnh và chân dung. nhưng bạn nói đúng rằng phương pháp này vẫn chưa giải quyết hoàn hảo các vấn đề phức tạp về giao diện người dùng. tôi vẫn đang tìm kiếm một cái gì đó tốt hơn để xử lý việc này.
datayeah

9

Kiểm tra MediaQuerylớp

Ví dụ, để tìm hiểu những kích thước của phương tiện truyền thông hiện tại (ví dụ, cửa sổ chứa ứng dụng của bạn), bạn có thể đọc các MediaQueryData.sizetài sản từ MediaQueryDatatrả về bởi MediaQuery.of: MediaQuery.of(context).size.

Vì vậy, bạn có thể làm như sau:

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

ý bạn là thay vì định vị sử dụng mediaQuery ??
praveen Dp

Tôi không hiểu những gì bạn đang cố gắng để làm
Aziza

sử dụng định vị, đệm bên trong ngăn xếp. tôi đã điều chỉnh nó thành kích thước màn hình. bây giờ để làm cho nó đáp ứng, tôi nên sử dụng mediaquery thay cho cái gì ??
praveen Dp

5

Bạn có thể lấy phần trăm chiều rộng hoặc chiều cao làm đầu vào cho kích thước tỷ lệ.

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

Trong đó hệ số ở cuối có giá trị làm cho Văn bản trông đẹp cho trình giả lập đang hoạt động.

Dưới đây là cách tôi thiết lập nó để tất cả các kích thước được chia tỷ lệ được tập trung ở một nơi. Bằng cách này, bạn có thể điều chỉnh chúng một cách dễ dàng và nhanh chóng chạy lại với Tải lại nóng mà không cần phải tìm kiếm các Media.of()cuộc gọi trong suốt mã.

  1. Tạo tệp để lưu trữ tất cả ánh xạ 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. Sau đó, tham chiếu rằng bất cứ khi nào bạn cần giá trị được chia tỷ lệ

    AppScale _scale = AppScale(context);

    // ... 

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

Cảm ơn câu trả lời trong bài đăng này


4

Tôi hơi khó xử lý các giải pháp của người khác (@datayeah & Vithani Ravi) ở đây, vì vậy tôi nghĩ rằng tôi sẽ chia sẻ nỗ lực của riêng mình trong việc giải quyết vấn đề tỷ lệ mật độ màn hình thay đổi này hoặc im lặng. Vì vậy, tôi tiếp cận vấn đề này từ một nền tảng vững chắc / cố định: tôi căn cứ tất cả quy mô của mình vào tỷ lệ cố định (không thay đổi) là 2: 1 (chiều cao: chiều rộng). Tôi có một lớp trợ giúp "McGyver" thực hiện tất cả công việc nặng nhọc (và chỉnh sửa mã hữu ích) trên ứng dụng của tôi. Lớp "McGyver" này chỉ chứa các phương thức tĩnh và các thành viên lớp hằng tĩnh.

PHƯƠNG PHÁP ĐỊNH KÍCH TỶ LỆ: Tôi chia tỷ lệ cả chiều rộng và chiều cao một cách độc lập dựa trên Tỷ lệ khung hình 2: 1. Tôi lấy các giá trị đầu vào chiều rộng & chiều cao và chia từng giá trị cho các hằng số chiều rộng & chiều cao và cuối cùng tính toán hệ số điều chỉnh để chia tỷ lệ các giá trị đầu vào chiều rộng và chiều cao tương ứng. Mã thực tế trông như sau:

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,
    );
  }

}

... ... ...

Sau đó, bạn sẽ chia tỷ lệ riêng các widget của mình (mà căn bệnh cầu toàn của tôi là TẤT CẢ UI của tôi) bằng một lệnh gọi tĩnh đơn giản tới phương thức "rsWidget ()" như sau:

  // 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!!

Điều thú vị là phương thức "rsWidget ()" trả về một widget !! Vì vậy, bạn có thể chỉ định tiện ích được chia tỷ lệ cho một biến khác như _rsBtnLoginđể sử dụng khắp nơi - hoặc bạn có thể chỉ cần sử dụng McGyver.rsWidget()lệnh gọi phương thức đầy đủ tại chỗ bên trongbuild() phương thức (chính xác cách bạn cần nó được định vị trong cây tiện ích con) và nó sẽ hoạt động hoàn hảo như bình thường.

Đối với những lập trình viên sắc sảo hơn: bạn sẽ nhận thấy rằng tôi đã sử dụng hai phương pháp chia tỷ lệ bổ sung McGyver.rsText()McGyver.rsDouble()(không được xác định trong đoạn mã ở trên) trong của tôi RaisedButton()- vì vậy về cơ bản tôi phát điên với công cụ chia tỷ lệ này ... bởi vì tôi yêu cầu ứng dụng của mình phải điểm ảnh tuyệt đối hoàn hảo ở bất kỳ tỷ lệ hoặc mật độ màn hình nào !! Tôi chia tỷ lệ số int, nhân đôi, khoảng đệm, văn bản (mọi thứ yêu cầu tính nhất quán của giao diện người dùng trên các thiết bị). Tôi chia tỷ lệ văn bản của mình chỉ dựa trên chiều rộng, nhưng chỉ định trục nào sẽ sử dụng cho tất cả các tỷ lệ khác (như đã làm với ScaleType.widthenum được sử dụng cho lệnh McGyver.rsDouble()gọi trong ví dụ mã ở trên).

Tôi biết điều này thật điên rồ - và còn rất nhiều việc phải làm trên chuỗi chính - nhưng tôi hy vọng ai đó sẽ thấy nỗ lực của tôi ở đây và giúp tôi tìm ra giải pháp tốt hơn (nhẹ hơn) cho tỷ lệ màn hình 1: 1 của tôi ác mộng.


1
@ Abbas.M - Có, tôi đã thực hiện một thay đổi nhỏ đối với dòng mã chia tỷ lệ [xem mã cập nhật] và tôi tin rằng đây là lần gần nhất tôi có thể đến với giải pháp chia tỷ lệ 1: 1 thực sự - Tôi đã thử khá nhiều tùy chọn để có được cái này. Vẫn còn một số vấn đề về tỷ lệ [edge-case] kỳ lạ với mã cập nhật này nhưng sự tương đồng về giao diện người dùng trên nhiều màn hình mật độ thực sự thuyết phục - sự khác biệt rất tinh tế có thể quan sát được giữa các màn hình với mã được cập nhật. Vui lòng cho tôi biết suy nghĩ của bạn - phản hồi được đánh giá cao.
SilSur

điều hiển nhiên về chuỗi chính, hãy di chuyển init và các lệnh gọi đến khối chính của ứng dụng init vì kích thước màn hình sẽ không thay đổi sau khi cài đặt ứng dụng, vì vậy bạn chỉ có chuỗi chính được nhấn một lần tại ứng dụng chứ không phải mỗi widget hiển thị
Fred Grott

@SilSur, giải pháp của bạn trông rất tuyệt. Bạn có phiền chia sẻ cả lớp McGyver không?
David

@David - Lớp McGyver là một lớp rất nặng (và dành riêng cho dự án). Cái tôi đã sử dụng trong ví dụ này có nhiều chức năng không liên quan đến vấn đề mở rộng giao diện người dùng. Vì vậy, việc tải lên toàn bộ lớp học là quá mức cần thiết / không hiệu quả. Tuy nhiên, tôi đã cải thiện lớp học một chút và đã đăng một phiên bản mã khác cho một câu hỏi SO khác . Có lẽ bạn có thể cập nhật mã tỷ lệ của mình dọc theo các dòng của mã cải tiến tại URL được cung cấp.
SilSur

4

Sau nhiều nghiên cứu và thử nghiệm, tôi đã phát triển một giải pháp cho một ứng dụng mà tôi hiện đang chuyển đổi từ Android / iOS sang Flutter.

Với Android và iOS, tôi đã sử dụng 'Hệ số tỷ lệ' được áp dụng cho các kích thước phông chữ cơ sở, hiển thị kích thước văn bản tương ứng với kích thước màn hình.

Bài viết này rất hữu ích: https://medium.com/flutter-community/flutter-effaries-scale-ui-according-to-dierence-screen-sizes-2cb7c115ea0a

Tôi đã tạo một StatelessWidget để lấy kích thước phông chữ của các kiểu chữ Material Design. Nhận kích thước thiết bị bằng MediaQuery, tính toán hệ số tỷ lệ, sau đó đặt lại kích thước văn bản Material Design. Widget có thể được sử dụng để xác định Chủ đề thiết kế Material Design tùy chỉnh.

Trình giả lập được sử dụng:

  • Pixel C - Máy tính bảng 9,94 "
  • Pixel 3 - Điện thoại 5,46 "
  • iPhone 11 Pro Max - Điện thoại 5,8 "

Với kích thước phông chữ tiêu chuẩn

Với kích thước phông chữ được chia tỷ lệ

set_app_theme.dart (Tiện ích 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 (Ứng dụng Demo)

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
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));

3
Có lẽ một lời giải thích về những gì đang diễn ra sẽ rất tuyệt vời vào lần tiếp theo bạn đăng "giải pháp"? Dù sao, tôi đã kiểm tra GitHub cho sự phụ thuộc này. Về cơ bản, nó là một lớp duy nhất (với 16 dòng mã) nhận các giá trị chiều rộng và chiều cao đầu vào và chia tỷ lệ dựa trên chiều rộng và chiều cao của màn hình dưới dạng phần trăm. Về cơ bản nó giống với giải pháp của @datayeah - chỉ khác là giải pháp này được đóng gói gọn gàng. Các vấn đề tương tự như datayeah áp dụng ở đây - không phải là một giải pháp tốt cho tỷ lệ 1: 1 trên các thiết bị có mật độ màn hình khác nhau. Vấn đề mật độ màn hình KHÔNG ĐƯỢC GIẢI QUYẾT bằng "giải pháp" này.
SilSur

1

Bạn có thể sử dụng MediaQuery cho thứ nguyên của cha mẹ hoặc FractionallySizedBox làm vùng chứa.


1

Cách tiếp cận vấn đề của tôi tương tự như cách datayeah đã làm. Tôi đã có rất nhiều giá trị chiều rộng và chiều cao được mã hóa cứng và ứng dụng trông ổn trên một thiết bị cụ thể. Vì vậy, tôi đã nhận được chiều cao màn hình của thiết bị và chỉ tạo một yếu tố để chia tỷ lệ các giá trị được mã hóa cứng.

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

trong đó 708 là chiều cao của thiết bị cụ thể.


1

Tôi cố gắng làm cho nó càng đơn giản càng tốt. thử cho nó một lần. Tôi tạo một tiện ích đáp ứng có chức năng getresponsivevalue chịu trách nhiệm cung cấp giá trị theo kích thước màn hình nếu bạn không chỉ định giá trị cho màn hình trung bình, màn hình lớn, chế độ ngang Theo mặc định, nó cung cấp giá trị được gán cho màn hình ngắn. một chào mừng nồng nhiệt cho bất kỳ câu hỏi. Tôi rất thích cải thiện

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

kiểm tra trang này từ flki wiki:

Tạo ứng dụng đáp ứng

Sử dụng lớp LayoutBuilder: Từ thuộc tính trình tạo của nó, bạn nhận được BoxConstraints. Kiểm tra các thuộc tính của ràng buộc để quyết định những gì sẽ hiển thị. Ví dụ: nếu maxWidth của bạn lớn hơn điểm ngắt chiều rộng, hãy trả về một đối tượng Scaffold với một hàng có danh sách ở bên trái. Nếu nó hẹp hơn, hãy trả về một đối tượng Scaffold với một ngăn chứa danh sách đó. Bạn cũng có thể điều chỉnh màn hình của mình dựa trên chiều cao của thiết bị, tỷ lệ khung hình hoặc một số thuộc tính khác. Khi các ràng buộc thay đổi (ví dụ: người dùng xoay điện thoại hoặc đặt ứng dụng của bạn vào giao diện người dùng dạng xếp trong Nougat), chức năng xây dựng sẽ chạy lại.


0

tạo tên tệp (app_config.dart) trong tên thư mục (responsive_screen) trong thư mục 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;
 }
}

sau đó:

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

Vấn đề này có thể được giải quyết bằng cách sử dụng MediaQuery.of (context)

Để có chiều rộng màn hình: MediaQuery.of(context).size.width

Để lấy Chiều cao màn hình: MediaQuery.of(context).size.height

Để biết thêm thông tin về đồng hồ Tiện ích MediaQuery, 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),

Điều này là tốt theo khuyến nghị của Google nhưng có thể không hoàn hảo.


0

Đã sử dụng ResponsiveBuilder hoặc 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(),
);

0

Bạn có thể sử dụng gói responsive_helper để làm cho ứng dụng của bạn đáp ứng.

Đó là một phương pháp rất dễ dàng để làm cho ứng dụng của bạn phản hồi nhanh. Chỉ cần xem trang ví dụ và sau đó bạn sẽ tìm ra cách sử dụng nó.


0

Cách dễ nhất để tạo giao diện người dùng đáp ứng cho các kích thước màn hình khác nhau là plugin Sizer .

Tạo giao diện người dùng đáp ứng trong mọi thiết bị có kích thước màn hình cũng như máy tính bảng. Kiểm tra nó plugin này ⬇️
https://pub.dev/packages/sizer

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

Sử dụng .h, .w, .spsau khi giá trị như thế này ⬇️

Thí dụ:

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)),
);

Tôi đã xây dựng nhiều ứng dụng đáp ứng với plugin này.


-2

Chiều rộng: MediaQuery.of(context).size.width,

Chiều cao: MediaQuery.of(context).size.height,

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.