Reputation: 85
I have a keyboard that I created in flutter where I need to be able to switch from uppercase to lower case when a button is pressed which is shown on my keyboard as the up arrow with a line below it. in both of my keyboard classes I have a conditional isCapital which changes between true and false every time the button is pressed. I also have a a fucnction which returns a widget where if isCapital is true it returns the capital keyboard and if false the lowercase keyboard. I placed this inside a container in my widget tree and am having a problem where the Boolean isCapital is being updated correctly and if I do a hot restart the keyboard changes from the capital to the lowercase board, but it does not change automatically, therefore when I press the button to change the board nothing happens. I am trying to understand what I need to do to implement this functionality where when I press the button the keyboard will change from one to the other.
Update: Also should probably mention that my keyboard class, as well as my capital key class and toggleKeyBoard() are all in a separate widget tree, so calling set state doesn't seem to work correctly.
I started looking into streams, not sure if my answer lies here.
Code for the capital button on the keyboard
class CapitalKey extends StatelessWidget
{
@override
Widget build(BuildContext context)
{
return Expanded(
flex: 100,
child: Padding(
padding: const EdgeInsets.all(6.0),
child: Material(
color: Color.fromRGBO(246, 246, 246, 1),
child: Container(
decoration: BoxDecoration(
border: Border.all(color: Color.fromRGBO(92, 103, 148, 1)),
borderRadius: BorderRadius.circular(5.0),
),
child: Center(
child: IconButton(
icon: Image.asset('assets/text_key/capital.png'),
onPressed: () {
isCapital = !isCapital;
},
),
),
),
),
),
);
}
}
Code for lowercase keyboard, uppercase keyboard just follows the same logic, and I implement the capital key on row three.
class KeyBoardLower extends StatelessWidget
{
KeyBoardLower({
required this.onTextInput,
required this.onBackspace,
});
final double width = 1200;
final double height = 80;
final ValueSetter<String> onTextInput;
final VoidCallback onBackspace;
void _textInputHandler(String text) => onTextInput.call(text);
void _backspaceHandler() => onBackspace.call();
Container buildRowOne()
{
return Container(
width: width,
height: height,
child: Row(
children: [
TextKey(
text: 'q',
onTextInput: _textInputHandler,
),
TextKey(
text: 'w',
onTextInput: _textInputHandler,
),
TextKey(
text: 'e',
onTextInput: _textInputHandler,
),
TextKey(
text: 'r',
onTextInput: _textInputHandler,
),
TextKey(
text: 't',
onTextInput: _textInputHandler,
),
TextKey(
text: 'y',
onTextInput: _textInputHandler,
),
TextKey(
text: 'u',
onTextInput: _textInputHandler,
),
TextKey(
text: 'i',
onTextInput: _textInputHandler,
),
TextKey(
text: 'o',
onTextInput: _textInputHandler,
),
TextKey(
text: 'p',
onTextInput: _textInputHandler,
),
BackspaceKey(
onBackspace: _backspaceHandler,
),
],
),
);
}
Container buildRowTwo()
{
return Container(
width: width,
height: height,
child: Row(
children: [
TextKey(
text: 'a',
onTextInput: _textInputHandler,
),
TextKey(
text: 's',
onTextInput: _textInputHandler,
),
TextKey(
text: 'd',
onTextInput: _textInputHandler,
),
TextKey(
text: 'f',
onTextInput: _textInputHandler,
),
TextKey(
text: 'g',
onTextInput: _textInputHandler,
),
TextKey(
text: 'h',
onTextInput: _textInputHandler,
),
TextKey(
text: 'j',
onTextInput: _textInputHandler,
),
TextKey(
text: 'k',
onTextInput: _textInputHandler,
),
TextKey(
text: 'l',
onTextInput: _textInputHandler,
),
EnterKey(),
],
),
);
}
Container buildRowThree()
{
return Container(
width: width,
height: height,
child: Row(
children: [
CapitalKey(),
TextKey(
text: 'z',
onTextInput: _textInputHandler,
),
TextKey(
text: 'x',
onTextInput: _textInputHandler,
),
TextKey(
text: 'c',
onTextInput: _textInputHandler,
),
TextKey(
text: 'v',
onTextInput: _textInputHandler,
),
TextKey(
text: 'b',
onTextInput: _textInputHandler,
),
TextKey(
text: 'n',
onTextInput: _textInputHandler,
),
TextKey(
text: 'm',
onTextInput: _textInputHandler,
),
TextKey(
text: '!',
onTextInput: _textInputHandler,
),
TextKey(
text: '?',
onTextInput: _textInputHandler,
),
CapitalKey(),
],
),
);
}
Container buildRowFour()
{
return Container(
width: width,
height: height,
child: Row(
children: [
NumberKey(),
TextKey(
text: ',',
onTextInput: _textInputHandler,
),
TextKey(
text: ' ',
onTextInput: _textInputHandler,
flex: 200,
),
TextKey(
text: '.',
onTextInput: _textInputHandler,
),
NumberKey(),
],
),
);
}
@override
Widget build(BuildContext context)
{
return SafeArea(
child: Padding(
padding: const EdgeInsets.only(left: 80),
child: Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
buildRowOne(),
buildRowTwo(),
buildRowThree(),
buildRowFour(),
],
),
),
),
);
}
}
Function I am using to change from one keyboard to the other, using a Boolean isCapital which I have initialized to false. I am calling this function which will return either keyboard to a container that I have on my main screen, if true return capital board and if false return lowercase board.
Widget toggleKeyboard()
{
if (isCapital == true) {
return KeyBoardCapital(
onTextInput: (myText) {
insertText(myText, toggleTextField()); //Accepts either myController1 or myController2 based on conditional
},
onBackspace: () {
backspace(toggleTextField());
},
);
} else {
return KeyBoardLower(
onTextInput: (myText) {
insertText(myText, toggleTextField());
},
onBackspace: () {
backspace(toggleTextField());
},
);
}
}
Upvotes: 0
Views: 636
Reputation: 181
Actually on pressing the CapitalKey
the value of isCapital
is getting changed but the widgets are not rebuilding, so you can't see the changes. A simple solution will be to call a setState
from the main screen assuming your main screen is a StatefulWidget
.
class CapitalKey extends StatelessWidget {
CapitalKey({
required this.onCapitalKeyPressed;
});
final VoidCallback onCapitalKeyPressed;
@override
Widget build(BuildContext context) {
// REST OF THE CODE IS SAME
child: IconButton(
icon: Image.asset('assets/text_key/capital.png'),
onPressed: onCapitalKeyPressed,
),
// REST OF THE CODE IS SAME
}
}
Similarly, you have to pass the onCapitalKeyPressed
to main screen from KeyBoardLower
and KeyBoardHigher
.
class KeyBoardLower extends StatelessWidget {
KeyBoardLower({
// ---
required this.onCapitalKeyPressed,
});
final VoidCallback onCapitalKeyPressed;
// REST OF THE CODE SAME
}
Now on the main screen toggle the flag isCapital
inside the setState
.
class MyKeyboard extends StatefulWidget {
const MyKeyboard({Key? key}) : super(key: key);
@override
State<MyKeyboard> createState() => _MyKeyboardState();
}
class _MyKeyboardState extends State<MyKeyboard> {
bool isCapital = false;
@override
Widget build(BuildContext context) {
return toggleKeyboard();
}
Widget toggleKeyboard() {
if (isCapital == true) {
return KeyBoardCapital(
// REST OF THE CODE SAME
onCapitalKeyPressed: () {
setState(() {
isCapital = !isCapital;
});
},
);
} else {
return KeyBoardLower(
// REST OF THE CODE SAME
onCapitalKeyPressed: () {
setState(() {
isCapital = !isCapital;
});
},
);
}
}
}
Hope it helps! Also let me know if I missed or misunderstood something :)
Upvotes: 1