Jak wyłączyć przycisk we Flutter?

122

Właśnie zaczynam rozumieć Flutter, ale mam problem ze zrozumieniem, jak ustawić stan włączenia przycisku.

W dokumentach mówi, aby ustawić onPressedna null, aby wyłączyć przycisk i nadać mu wartość, aby go włączyć. Jest to w porządku, jeśli przycisk nadal pozostaje w tym samym stanie przez cały cykl życia.

Odnoszę wrażenie, że muszę stworzyć niestandardowy widget Stateful, który pozwoli mi w jakiś sposób zaktualizować stan włączenia przycisku (lub wywołanie zwrotne onPressed).

Więc moje pytanie brzmi: jak miałbym to zrobić? Wydaje się, że jest to dość proste wymaganie, ale nie mogę znaleźć niczego w dokumentacji, jak to zrobić.

Dzięki.

chris84948
źródło
Czy możesz wyjaśnić, co masz na myśli, mówiąc: „To jest w porządku, jeśli przycisk pozostaje w tym samym stanie przez cały cykl życia”. ?
Seth Ladd

Odpowiedzi:

133

Myślę, że możesz chcieć wprowadzić kilka funkcji pomocniczych do buildswojego przycisku, a także widget Stateful wraz z pewną właściwością do wyłączenia.

  • Użyj StatefulWidget / State i utwórz zmienną do przechowywania twojego warunku (np. isButtonDisabled)
  • Na początku ustaw to na true (jeśli tego chcesz)
  • Podczas renderowania przycisku nie ustawiaj bezpośrednioonPressed wartości ani na nullani na jakąś funkcjęonPressed: () {}
  • Zamiast tego ustaw ją warunkowo, używając funkcji trójargumentowej lub pomocniczej (przykład poniżej)
  • Sprawdź isButtonDisabledjako część tego warunku i zwróć jedną nulllub jakąś funkcję.
  • Kiedy przycisk jest wciśnięty (lub kiedy chcesz wyłączyć przycisk) użyj, setState(() => isButtonDisabled = true)aby odwrócić zmienną warunkową.
  • Flutter ponownie wywoła build()metodę z nowym stanem, a przycisk zostanie wyrenderowany z nullobsługą prasy i zostanie wyłączony.

Oto trochę więcej kontekstu przy użyciu projektu licznika Flutter.

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => new _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;
  bool _isButtonDisabled;

  @override
  void initState() {
    _isButtonDisabled = false;
  }

  void _incrementCounter() {
    setState(() {
      _isButtonDisabled = true;
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text("The App"),
      ),
      body: new Center(
        child: new Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            new Text(
              'You have pushed the button this many times:',
            ),
            new Text(
              '$_counter',
              style: Theme.of(context).textTheme.display1,
            ),
            _buildCounterButton(),
          ],
        ),
      ),
    );
  }

  Widget _buildCounterButton() {
    return new RaisedButton(
      child: new Text(
        _isButtonDisabled ? "Hold on..." : "Increment"
      ),
      onPressed: _isButtonDisabled ? null : _incrementCounter,
    );
  }
}

W tym przykładzie używam trójnika w wierszu, aby warunkowo ustawić Texti onPressed, ale może być bardziej odpowiednie, aby wyodrębnić to do funkcji (możesz użyć tej samej metody, aby zmienić tekst przycisku):

Widget _buildCounterButton() {
    return new RaisedButton(
      child: new Text(
        _isButtonDisabled ? "Hold on..." : "Increment"
      ),
      onPressed: _counterButtonPress(),
    );
  }

  Function _counterButtonPress() {
    if (_isButtonDisabled) {
      return null;
    } else {
      return () {
        // do anything else you may want to here
        _incrementCounter();
      };
    }
  }
Ashton Thomas
źródło
3
Musisz dodać funkcję grubej strzałki jako argument, w przeciwnym razie funkcja _incrementCounter () zostanie wywołana od razu po włączeniu przycisku. W ten sposób będzie faktycznie czekać, aż przycisk zostanie kliknięty: OnPressed powinien wyglądać tak:onPressed: _isButtonDisabled ? null : () => _incrementCounter
Vit Veres
2
@vitVeres, które zwykle jest prawdziwe, ale _counterButtonPress () zwraca funkcję, return () {}więc jest to zamierzone. Nie chcę tutaj używać grubej strzałki, ponieważ chcę, aby funkcja wykonywała się, wracała nulli wyłączała przycisk.
Ashton Thomas,
@AshtonThomas Tak, w wyodrębnionej metodzie _counterButtonPress () jest dokładnie tak, jak wyjaśniłeś, ale odwoływałem się do kodu z operatorem trójskładnikowym, zanim zasugerowałeś wyodrębnienie. W pierwszym przykładzie spowoduje to wykonanie metody _incrementCounter (), gdy przycisk powinien być włączony. Następnym razem spróbuję dokładniej wskazać, co mam na myśli :)
Vit Veres
31
Co było złego w korzystaniu z disablednieruchomości, zespół Flutter? To po prostu nie jest intuicyjne: - /
Curly,
1
właściwą drogą jest AbsorbPointer lub IgnorePointer. Po prostu widżet zamiast logiki z ustawieniem onPressed na null.
ejdrian313
99

Według dokumentów:

„Jeśli wywołanie zwrotne onPressed ma wartość null, przycisk zostanie wyłączony i domyślnie będzie przypominał płaski przycisk w disabledColor”.

https://docs.flutter.io/flutter/material/RaisedButton-class.html

Więc możesz zrobić coś takiego:

    RaisedButton(
      onPressed: calculateWhetherDisabledReturnsBool() ? null : () => whatToDoOnPressed,
      child: Text('Button text')
    );
Steve Alexander
źródło
2
Sądząc po dokumentacji, w ten sposób ma zostać wdrożony. Z przyjętymi właściwości odpowiedziami jak disabledElevation, disabledColori DisabledTextColornie będzie działać zgodnie z przeznaczeniem.
Joel Broström
Pff dzięki za to Steve, nie planował przechodzić przez cały kod aktualnie akceptowanej odpowiedzi. @ chris84948, rozważ zmianę tego na zaakceptowaną odpowiedź.
CularBytes
42

Prosta odpowiedź brzmi: onPressed : nullwyłączono przycisk.

BINAY THAPA MAGAR
źródło
17

Oprawa

onPressed: null // disables click

i

onPressed: () => yourFunction() // enables click
CopsOnRoad
źródło
1
W tym rozwiązaniu wartość onPressedjest zawsze funkcją, więc przycisk jest renderowany jako „klikalny”, chociaż będzie ignorował zdarzenie click, jeśli isEnabledwłaściwość jest ustawiona. Aby naprawdę wyłączyć przycisk, użyjRaisedButton(onPressed: isEnabled ? _handleClick : null
Curly
15

W przypadku określonej i ograniczonej liczby widżetów zawijanie ich w widżet IgnorePointer robi dokładnie to: gdy jego ignoringwłaściwość jest ustawiona na true, pod-widget (a właściwie całe poddrzewo) nie jest klikalny.

IgnorePointer(
    ignoring: true, // or false
    child: RaisedButton(
        onPressed: _logInWithFacebook,
        child: Text("Facebook sign-in"),
        ),
),

W przeciwnym razie, jeśli zamierzasz wyłączyć całe poddrzewo, zajrzyj do AbsorbPointer ().

Edmond
źródło
9

Funkcje włączania i wyłączania są takie same dla większości widżetów.

Np. Przycisk, przełącznik, pole wyboru itp.

Po prostu ustaw onPressedwłaściwość, jak pokazano poniżej

onPressed : nullzwraca Wyłączony widget

onPressed : (){}lub onPressed : _functionNamezwraca włączony widżet

Vicky Salunkhe
źródło
7

Możesz również użyć AbsorbPointer i możesz go użyć w następujący sposób:

AbsorbPointer(
      absorbing: true, // by default is true
      child: RaisedButton(
        onPressed: (){
          print('pending to implement onPressed function');
        },
        child: Text("Button Click!!!"),
      ),
    ),

Jeśli chcesz dowiedzieć się więcej o tym widżecie, możesz sprawdzić poniższy link Flutter Docs

Juanes30
źródło
2
Ignore- / AbsorbPointer nie traktuje stylów niepełnosprawnych tylko jako PRZYPOMNIENIE :-)
Pascal
5

To moim zdaniem najłatwiejszy sposób:

RaisedButton(
  child: Text("PRESS BUTTON"),
  onPressed: booleanCondition
    ? () => myTapCallback()
    : null
)
MatPag
źródło