Idiomas: Inglês, Português Brasileiro (este arquivo), Espanhol.
- Sobre Get
- Instalando e iniciando
- Os três pilares
- Utilidades
- Breaking Changes da versão 2 para 3
- Porque eu fiz esse package
Sobre Get
- Get é uma biblioteca poderosa e extra-leve para Flutter. Ela combina um gerenciador de estado de alta performance, injeção de dependência inteligente e gerenciamento de rotas de uma forma rápida e prática.
- Get não é para todos, seu foco é:
- Performance: Já que gasta o mínimo de recursos
- Produtividade: Usando uma sintaxe fácil e agradável
- Organização: Que permite o total desacoplamento da View e da lógica de negócio.
- Get vai economizar horas de desenvolvimento, e vai extrair a performance máxima que sua aplicação pode entregar, enquanto é fácil para iniciantes e preciso para experts.
- Navegue por rotas sem
context
, abraDialog
s,Snackbar
s ouBottomSheet
s de qualquer lugar no código, gerencie estados e injete dependências de uma forma simples e prática. - Get é seguro, estável, atualizado e oferece uma enorme gama de APIs que não estão presentes no framework padrão.
- GetX não é um
bloc
da vida. Ele tem uma variedade de recursos que te permite começar a programar sem se preocupar com nada, mas cada um desses recursos estão em um container separado, ou seja, nenhuma depende da outra para funcionar. Elas só são inicializadas após o uso. Se você usa apenas o gerenciador de estado, apenas ele será compilado. Teste você mesmo, vá no repositório de benchmark do getX e perceberá: usando somente o gerenciador de estado do Get, a aplicação ficou mais leve do que outros projetos que também estão usando só o gerenciador de estado, porque nada que não seja usado será compilado no seu código, e cada recuro do GetX foi feito para ser muito leve. O mérito vem também do AOT do próprio Flutter que é incrível, e consegue eliminar recursos não utilizados de uma forma que nenhum outro framework consegue.
GetX faz seu desenvolvimento mais produtivo, mas quer deixá-lo mais produtivo ainda? Adicione a extensão GetX extension no seu VSCode. Não disponível para outras IDEs por enquanto.
Quer contribuir no projeto? Nós ficaremos orgulhosos de ressaltar você como um dos colaboradores. Aqui vai algumas formas em que você pode contribuir e fazer Get (e Flutter) ainda melhores
- Ajudando a traduzir o README para outras linguagens.
- Adicionando mais documentação ao README (até o momento, nem metade das funcionalidades do Get foram documentadas).
- Fazendo artigos/vídeos ensinando a usar o Get (eles serão inseridos no README, e no futuro na nossa Wiki).
- Fazendo PR's (Pull-Requests) para código/testes.
- Incluindo novas funcionalidades.
Qualquer contribuição é bem-vinda!
Instalando e iniciando
Adicione Get ao seu arquivo pubspec.yaml
dependencies:
get:
Importe o get nos arquivos que ele for usado:
import 'package:get/get.dart';
Os três pilares
Gerenciamento de estado
Veja uma explicação mais completa do gerenciamento de estado aqui
O app 'Counter' criado por padrão no com o comando flutter create
tem mais de 100 linhas(incluindo os comentários). Para demonstrar o poder do Get, irei demonstrar como fazer o mesmo 'Counter' mudando o estado em cada toque trocando entre páginas e compartilhando o estado entre telas. Tudo de forma organizada, separando a lógica de negócio da View, COM SOMENTE 26 LINHAS INCLUINDO COMENTÁRIOS
- Passo 1:
Troque
MaterialApp
paraGetMaterialApp
void main() => runApp(GetMaterialApp(home: Home()));
-
Obs: Isso não modifica o
MaterialApp
do Flutter, GetMaterialApp não é uma versão modificada do MaterialApp, é só um Widget pré-configurado, que tem como child o MaterialApp padrão. Você pode configurar isso manualmente, mas definitivamente não é necessário. GetMaterialApp vai criar rotas, injetá-las, injetar traduções, injetar tudo que você precisa para navegação por rotas (gerenciamento de rotas). Se você quer somente usar o gerenciadro de estado ou somente o gerenciador de dependências, não é necessário usar o GetMaterialApp. Ele somente é necessário para:- Rotas
- Snackbars/bottomsheets/dialogs
- apis relacionadas a rotas e a ausência de
context
- Internacionalização
Passo 2: Cria a sua classe de regra de negócio e coloque todas as variáveis, métodos e controllers dentro dela. Você pode fazer qualquer variável observável usando um simples
.obs
class Controller extends GetxController{
var count = 0.obs;
increment() => count.value++;
}
- Passo 3: Crie sua View usando StatelessWidget, já que, usando Get, você não precisa mais usar StatefulWidgets.
class Home extends StatelessWidget {
// Instancie sua classe usando Get.put() para torná-la disponível para todas as rotas subsequentes
final Controller c = Get.put(Controller());
@override
Widget build(context) => Scaffold(
appBar: AppBar(title: Obx(
() => Text("Total of clicks: " + c.count.string))),
// Troque o Navigator.push de 8 linhas por um simples Get.to(). Você não precisa do 'context'
body: Center(child: RaisedButton(
child: Text("Ir pra Outra tela"), onPressed: () => Get.to(Outra()))),
floatingActionButton: FloatingActionButton(child:
Icon(Icons.add), onPressed: c.increment));
}
class Outra extends StatelessWidget {
// Você pode pedir o Get para encontrar o controller que foi usado em outra página e redirecionar você pra ele.
final Controller c = Get.find();
@override
Widget build(context) => Scaffold(body: Center(child: Text(c.count.string)));
}
Esse é um projeto simples mas já deixa claro o quão poderoso o Get é. Enquanto seu projeto cresce, essa diferença se torna bem mais significante.
Get foi feito para funcionar com times, mas torna o trabalho de um desenvolvedor individual simples.
Melhore seus prazos, entregue tudo a tempo sem perder performance. Get não é para todos, mas se você identificar com o que foi dito acima, Get é para você!
Explicação completa
Veja uma explicação mais completa do gerenciamento de estado aqui
Gerenciamento de rotas
Veja uma explicação mais completa do gerenciamento de rotas aqui
Para navegar para uma próxima tela:
Get.to(ProximaTela());
Para fechar snackbars, dialogs, bottomsheets, ou qualquer coisa que você normalmente fecharia com o Navigator.pop(context)
(como por exemplo fechar a View atual e voltar para a anterior):
Get.back();
Para ir para a próxima tela e NÃO deixar opção para voltar para a tela anterior (bom para SplashScreens, telas de login e etc.):
Get.off(ProximaTela());
Para ir para a próxima tela e cancelar todas as rotas anteriores (útil em telas de carrinho, votações ou testes):
Get.offAll(ProximaTela());
Para navegar para a próxima rota, e receber ou atualizar dados assim que retornar da rota:
var dados = await Get.to(Pagamento());
Notou que você não precisou usar context
para fazer nenhuma dessas coisas? Essa é uma das maiores vantagens de usar o gerenciamento de rotas do GetX. Com isso, você pode executar todos esse métodos de dentro da classe Controller, sem preocupações.
Explicação completa
GetX funciona com rotas nomeadas também! Veja uma explicação mais completa do gerenciamento de rotas aqui
Gerenciamento de Dependência
Veja uma explicação mais completa do gerenciamento de dependência aqui
- Nota: Se você está usando o gerenciador de estado do Get, você não precisa se preocupar com isso, só leia a documentação, mas dê uma atenção a api
Bindings
, que vai fazer tudo isso automaticamente para você.
Já está usando o Get e quer fazer seu projeto o melhor possível? Get tem um gerenciador de dependência simples e poderoso que permite você pegar a mesma classe que seu Bloc ou Controller com apenas uma linha de código, sem Provider context, sem inheritedWidget:
Controller controller = Get.put(Controller()); // Em vez de Controller controller = Controller();
Em vez de instanciar sua classe dentro da classe que você está usando, você está instanciando ele dentro da instância do Get, que vai fazer ele ficar disponível por todo o App
Para que então você possa usar seu controller (ou uma classe Bloc) normalmente
controller.fetchApi();
Agora, imagine que você navegou por inúmeras rotas e precisa de dados que foram deixados para trás em seu controlador. Você precisaria de um gerenciador de estado combinado com o Provider ou Get_it, correto? Não com Get. Você só precisa pedir ao Get para "procurar" pelo seu controlador, você não precisa de nenhuma dependência adicional para isso:
Controller controller = Get.find();
// Sim, parece Magia, o Get irá descobrir qual é seu controller, e irá te entregar.
// Você pode ter 1 milhão de controllers instanciados, o Get sempre te entregará o controller correto.
// Apenas se lembre de Tipar seu controller, final controller = Get.find(); por exemplo, não irá funcionar.
E então você será capaz de recuperar os dados do seu controller que foram obtidos anteriormente:
Text(controller.textFromApi);
Procurando por lazyLoading
?(carregar somente quando for usar) Você pode declarar todos os seus controllers, e eles só vão ser inicializados e chamados quando alguém precisar. Você pode fazer isso
Get.lazyPut<Service>(()=> ApiMock());
/// ApiMock só será chamado quando alguém usar o Get.find<Service> pela primeira vez
Explicação completa
Veja uma explicação mais completa do gerenciamento de dependência aqui
Utilidades
Mudar tema (changeTheme)
Por favor não use widget acima do GetMaterialApp para atualizar o tome. Isso pode causar keys duplicadas. Várias pessoas estão acostumadas com o jeito normal de criar um Widget ThemeProvider
só pra alterar o thema do app, mas isso definitivamente NÃO é necessário no Get.
Você pode criar seu tema customizado e simplesmente adicionar dentro do Get.changeTheme
sem nenhum boilerplate para isso:
Get.changeTheme(ThemeData.light())
Se você quer criar algo como um botão que muda o tema com o toque, você pode combinar duas APIs Get pra isso: a API que checa se o tema dark está sendo aplicado, e a API de mudar o tema, e colocar isso no onPressed:
Get.changeTheme(
Get.isDarkMode
? ThemeData.light()
: ThemeData.dark()
)
Quando o modo Dark está ativado, ele vai trocar pro modo light, e vice versa.
Se você quiser saber mais como trocar o tema, você pode seguir esse tutorial no Medium que até ensina persistência do tema usando Get (e SharedPreferences):
- Dynamic Themes in 3 lines using Get - Tutorial by Rod Brown.
Outras APIs avançadas
// fornece os arguments da tela atual
Get.arguments
// fornece os arguments da rota anterior
Get.previousArguments
// fornece o nome da rota anterior
Get.previousRoute
// fornece a rota bruta para acessar por exemplo, rawRoute.isFirst()
Get.rawRoute
// fornece acesso a API de rotas de dentro do GetObserver
Get.routing
// checa se o snackbar está aberto
Get.isSnackbarOpen
// checa se o dialog está aberto
Get.isDialogOpen
// checa se o bottomsheet está aberto
Get.isBottomSheetOpen
// remove uma rota.
Get.removeRoute()
// volta repetidamente até o predicate retorne true.
Get.until()
// vá para a próxima rota e remove todas as rotas
//anteriores até que o predicate retorne true.
Get.offUntil()
// vá para a próxima rota nomeada e remove todas as
//rotas anteriores até que o predicate retorne true.
Get.offNamedUntil()
// retorna qual é a plataforma
//(Esse método é completamente compatível com o FlutterWeb,
//diferente do método do framework "Platform.isAndroid")
GetPlatform.isAndroid/isIOS/isWeb...
// Equivalente ao método: MediaQuery.of(context).size.width ou height, mas é imutável. Significa que não irá atualizar mesmo que o tamanho da tela mude (como em navegadores ou app desktop)
Get.height
Get.width
// Se você precisa de um width/height adaptável (como em navegadores em que a janela pode ser redimensionada) você precisa usar 'context'
Get.context.width
Get.context.height
// forncece o context da tela em qualquer lugar do seu código.
Get.context
// fornece o context de snackbar/dialog/bottomsheet em qualquer lugar do seu código.
Get.contextOverlay
/// similar to MediaQuery.of(this).padding
Get.mediaQueryPadding()
/// similar to MediaQuery.of(this).viewPadding
Get.mediaQueryViewPadding()
/// similar to MediaQuery.of(this).viewInsets;
Get.mediaQueryViewInsets()
/// similar to MediaQuery.of(this).orientation;
Get.orientation()
/// check if device is on landscape mode
Get.isLandscape()
/// check if device is on portrait mode
Get.isPortrait()
/// similar to MediaQuery.of(this).devicePixelRatio;
Get.devicePixelRatio()
/// similar to MediaQuery.of(this).textScaleFactor;
Get.textScaleFactor()
/// get the shortestSide from screen
Get.mediaQueryShortestSide()
/// True if width be larger than 800
Get.showNavbar()
/// True if the shortestSide is smaller than 600p
Get.isPhone()
/// True if the shortestSide is largest than 600p
Get.isSmallTablet()
/// True if the shortestSide is largest than 720p
Get.isLargeTablet()
/// True if the current device is Tablet
Get.isTablet()
Configurações Globais opcionais e configurações manuais
GetMaterialApp configura tudo para você, mas se quiser configurar Get manualmente, você pode.
MaterialApp(
navigatorKey: Get.key,
navigatorObservers: [GetObserver()],
);
Você também será capaz de usar seu próprio Middleware dentro do GetObserver, isso não irá influenciar em nada.
MaterialApp(
navigatorKey: Get.key,
navigatorObservers: [
GetObserver(MiddleWare.observer) // Aqui
],
);
Você pode criar Configurações Globais para o Get. Apenas adicione Get.config
ao seu código antes de usar qualquer rota ou faça diretamente no seu GetMaterialApp
GetMaterialApp(
enableLog: true,
defaultTransition: Transition.fade,
opaqueRoute: Get.isOpaqueRouteDefault,
popGesture: Get.isPopGestureEnable,
transitionDuration: Get.defaultDurationTransition,
defaultGlobalState: Get.defaultGlobalState,
);
Get.config(
enableLog = true,
defaultPopGesture = true,
defaultTransition = Transitions.cupertino
)
Breaking Changes da versão 2 para 3
Tipagem Rx
Antes | Depois |
---|---|
StringX | RxString |
IntX | RxInt |
MapX | RxMax |
ListX | RxList |
NumX | RxNum |
RxDouble | RxDouble |
RxController e GetBuilder se uniram
RxController e GetBuilder agora viraram um só, você não precisa mais memorizar qual controller quer usar, apenas coloque GetxController
, vai funcionar para os dois gerenciamento de estados
//Gerenciador de estado simples
class Controller extends GetXController {
String nome = '';
void atualizarNome(String novoNome) {
nome = novoNome;
update()
}
}
class Controller extends GetXController {
final nome = ''.obs;
// não precisa de um método direto pra atualizar o nome
// só usar o nome.value
}
Rotas nomeadas
Antes:
GetMaterialApp(
namedRoutes: {
'/': GetRoute(page: Home()),
}
)
Agora:
GetMaterialApp(
getPages: [
GetPage(name: '/', page:()=> Home()),
]
)
Porque essa mudança
Frequentemente, pode ser necessário decidir qual pagina vai ser mostrada ao usuário a partir de um parâmetro, como um token de login. A forma abordada anteriormente não era flexível, já que não permitia isso.
Inserir a página numa função reduziu significativamente o consumo de RAM, já que as rotas não são alocadas na memória desde o app inicia, e também permite fazer esse tipo de abordagem:
GetStorage box = GetStorage();
GetMaterialApp(
getPages: [
GetPage(name: '/', page:(){
return box.hasData('token') ? Home() : Login();
})
]
)
Porque eu fiz esse package
O problema que esse package tenta resolver é possuir a maioria das funções que preciso num package só.
Um dia, quando eu atualizei um dos meus apps no trabalho para o Flutter 1.9, algo ruim aconteceu: Tudo quebrou.
Todas as bibliotecas pararam de funcionar, na atualização foi bloqueado o uso do hifen "-". Alguns atualizaram seus packages, outros não. Outros eu tive que olhar o porque do projeto não compilar. Outros simplesmente se tornaram incompatíveis com a versão atual, como o image_extended
que eu até ofereci um PR lá pra conseguir corrigir, e tudo isso por causa de um simples update.
Eu perdi 2 dias de trabalho só procurando por erros pra saber de onde eles vieram.
Eu confesso que foi uma das situações mais estressantes que eu já passei na vida. Foi exatamente nesse dia que eu decidi colocar tudo num package.
Eu sei que parece que esse package é feito só pra sanar minha experiência pessoal, mas eu sou um programador, e eu tento resolver problemas sempre da perspectiva do programador. Eu não me importo em nada mais que fazer a minha vida e de outros programadores mais fácil com esse package.
Sempre que eu passo por uma experiência frustrante, eu escrevo no meu caleundário, e tento resolver depois de completar o projeto.
E então eu decidi fazer um package que tenha três coisas que eu sempre uso: Gerenciamento de Estado, de rotas e de dependências. Depois eu fiz também internacionalização, e persistênsia de dados (estilo Hive)
Essa biblioteca sempre será atualizada e terá sempre nova features sendo implementadas. Sinta-se livre para oferecer PRs e contribuir com o package.