Flutter margin onFocus FocusNode - flutter

How do I set the margin from the edge when the focus hits a specific FocusNode?
As you can see from the video, there is an indentation on top of the buttons, but when you scroll the screen and return the focus to the button, it sticks to the top of the screen, it's understandable, the button is on the screen and in focus, but how to make a small offset from the top?

Try something like this:
Container(
margin: EdgeInsets.only(top: (focusnode.hasFocus) ? 10 : 0),
child: Text((focusnode.hasFocus) ? 'In Focus' : 'No Focus');
);

Related

When using Flutter Visibility widget, can the change in visibility be animated?

I have a column holding a number of containers. The top and bottom containers are always shown, but the ones between sit inside a Visibility widget. If the user taps the screen, the middle containers are made visible, and then are made invisible again on the next tap. So essentially, the column expands and contracts each time it's tapped.
I'd like the expansion and contraction to happen a bit more gracefully - currently it looks very harsh when the middle containers just suddenly appear. Is there any way of animating the way in which the containers are made visible and hidden? Or should I be looking at using a totally different Widget than Visibility?
You can use an animated crossfade. Make the first child as SizedBox.shrink() and second child as the widget that you wish to display and it should be animating as expected. And switch according to the requirement
bool _first = true;
AnimatedCrossFade(
duration: const Duration(seconds: 1),
firstChild: const SizedBox.shrink(),
secondChild: const FlutterLogo(style: FlutterLogoStyle.stacked, size: 100.0),
crossFadeState: _first ? CrossFadeState.showFirst : CrossFadeState.showSecond,
)
Alter the value of _first to true or false.

Flutter: TextField will not scroll down when new lines are added

Update: this problem may be because of setting the TextField's 'readOnly' attribute to true. If so, I still need to make sure the keyboard does not pop up, since I set readOnly to true to disable the keyboard.
BACKGROUND
My app adds letters and newlines from a custom button widgets to a display that has a TextField widget. I do not use a keyboard for this. I use the Provider package and a ChangeNotifier called AppBrain to manage state. AppBrain has the text information and edits it when a letter is selected from the selection bar.
The textfield is a scrollable widget when there are too many lines to fit in its dimensions. But whenever I add letters and a new line of text is created, the textfield does not scroll down and the cursor and edited line is obscured.
I would like to know an easy way to scroll until the cursor is visible again. (When the cursor is at the end of the text, I can scroll to the bottom. When it is in the middle of the text, I just need to scroll it one line down.)
POSSIBLE FIXES
When I reenable the keyboard to edit the TextField, it does it automatically. If anyone knows how the keyboard edits the TextField, I might be able to add that to my addWord function.
I tried using a ScrollController to scroll the TextField using its animateTo() function. The problem I have is that I usually need to just scroll down 1 line, but I don't have the exact pixel height of my lines of text. I also don't know when a line wraps to a new line, which would require a scroll down.
Perhaps if I had the position of my cursor, I could use it along with my TextField's dimensions to scroll down accordingly.
Picture of my app
CODE
Textfield widget in Text Display
Portion of code in Text Display
...
Positioned(//Text Display
top:0,
left:0,
width:kScreenDim.dx,
height:290,
child: Container(
color: kAppBarBackgroundColor,
child: Container(
padding: EdgeInsets.only(left: kTextMargin),
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
topLeft:Radius.elliptical(17,20),
topRight: Radius.elliptical(17,20)
),
color:kTextDisplayColor
),
child: Consumer<AppBrain>(
builder: (context,appBrain, child)=> TextField(// <<=====
controller: appBrain.textDisplayController,
scrollController: appBrain.textDisplayScrollController,
readOnly: true,
autofocus: true,
showCursor: true,
maxLines: null,
decoration: null,
cursorColor: Colors.red,
style: TextStyle(fontSize: kTextFontSize,)
),
),
),
),
),
...
Enter Button
Example of a button that adds a letter to the TextField
BottomButton(//ENTER BUTTON
onPressed: () {
var appBrain = Provider.of<AppBrain>(context, listen:false);// <<===
appBrain.addWord('\n');
},
label: 'Enter',
color: kEnterButtonColor,
)
App Brain
Relevant portions of AppBrain, a ChangeNotifier. The main summary of addWord is that I directly edit textDisplayController.text and textDisplayController.selection.
class AppBrain with ChangeNotifier {
...
TextEditingController textDisplayController = TextEditingController();
ScrollController textDisplayScrollController = ScrollController();
...
...
void addWord (String aWord){//Inserts/replaces word into text of TextDisplay
//DIRECTLY EDITS textDisplayController.text and textDisplayController.selection
String displayText = textDisplayController.text;
List<int> selectionRange = getSelectionRange();
int cursorCharIndex = selectionRange[0]; //position in text
//position in _numTChars
int newCursorDisplayIndex = getCursorDisplayIndex(cursorCharIndex);
//Update text and _numTChar.
//If there is a highlighted selection of text to be replaced,
if (selectionRange[0]!=selectionRange[1]){
int lidx = selectionRange[0];
int ridx = selectionRange[1];
int lDisplayIdx = getCursorDisplayIndex(lidx);
int rDisplayIdx = getCursorDisplayIndex(ridx);
textDisplayController.text = displayText.substring(0,lidx) + aWord; <<===
if (ridx < displayText.length) {
textDisplayController.text += displayText.substring(ridx);
}
_numTChars[lDisplayIdx] = aWord.length;
_numTChars = _numTChars.sublist(0, lDisplayIdx+1) +
_numTChars.sublist(rDisplayIdx);
}else {//Insert character at the cursor
if (displayText.length == 0 || cursorCharIndex == displayText.length) {
textDisplayController.text += aWord;
} else {
textDisplayController.text = displayText.substring(0, cursorCharIndex)+
aWord + displayText.substring(cursorCharIndex);
}
_numTChars.insert(newCursorDisplayIndex, aWord.length);
}
//place the cursor in the correct position.
cursorCharIndex += aWord.length;
// <<===
textDisplayController.selection = TextSelection(
baseOffset: cursorCharIndex,
extentOffset: cursorCharIndex
);
notifyListeners();
}
...
}
When keyboard pops up it covers bottom of you widget. you should use MediaQuery to get bottom padding after keyboard pops up.
wrap your page in a Padding widget and set the bottom like this.
Padding(
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom,
),
child: YourWidget()
when keyboard is not visible the value of
MediaQuery.of(context).viewInsets.bottom is zero, but when keyboard pops up the value changes to somethong like 253.6.

What is the exact position of the BackButton in an AppBar? Is kToolbarHeight 4px off?

Description
How do you position a custom back button on the exact location where the back button usually would be in an app bar?
Is kToolbarHeight 4px off?
Goal
I fade in the original app bar as the bottom sheet is pushed to the top.
Currently I'm using a Stack widget that positions the back button with kToolbarHeight from the top, but apparently that doesn't really match (It's rather kToolbarHeight - 4px).
I use a custom implementation of a back button, but this problem persists with the original backButton widget too.
Stack(
children: [
Map(...),
const Positioned(
top: kToolbarHeight,
left: 4.0,
child: CustomBackButton(),
),
],
);
Groundwork
I've looked it up in the dev tools and the original source code but couldn't find a reliable constant nor anything helpful.
Try like this:
Give your CustomBackButton() widget the dimensions of a square of kToolbarHeight side.
Inside your Stack, add a SafeArea child, into which you position the CustomBackButton() in the top left corner. That should place it in the right position.

Make first item (or padding) of SingleChildScrollView not scrollable and delegate the touch events

I have a Stack with two Columns.
First column contains contains only one child (1) with InteractiveViewer which has defined height (for example 250). It changes its content's zoom and translation based on scroll offset of SingleChildScrollView from second column. It shouldn't be pushed out of the screen while scrolling, so it's under the scroll view in a stack.
The second column have SingleChildScrollView with top padding (2) OR first view (3) that matches the (1) height.
Now I'd like to make the top padding (2) or view (3) not scroll the SingleChildScrollView but pass those touch events to InteractiveViewer. Doesn't matter whether the solution use padding or empty view, I just wanted to note here than what I want can be achieved with padding or view. I tried both but failed.
I tried the GestureDetector, IgnorePointer and AbsorbPointer, but seems like the SingleChildScrollView always get the touch events. I haven't found a way to make the top padding not scrollable too.
Basically I'd like to achieve something similar to the attached gif, except that I don't need the "Collapsing Header" text animation and app bar. Just pay attention to the mountains that hide below the scroll view. The scroll view should take entire screen once the scroll offset is equal padding/view height (250 in this example).
Is that possible somehow? My logic behind InteractiveViewer is way more complicated than the example provided below, I just simplified it to make the question easier to understand.
Stack(children: [
Column(
children: [
Container( // (1) Widget that should get the touch events
height: 250,
child: InteractiveViewer(...)
),
],
),
Column(
children: [
Expanded(
child: SingleChildScrollView(
padding: EdgeInsets.only(top: 250), // (2) Either not scrollable padding
child: Column(
children: [
Container(height: 250), // (3) or not scrollable first item
Container(...)
],
),
),
),
],
),
]);

flutter - fab button animation which will go to top from bottom

I need help with the animation, when I click on the FAB icon in the first screen the icon will go up with animation and the other screen (shown in second image) should be displayed with animation like curtain. And the fab icon should be set in the app bar just like second image.
Bottom menu should be there in both of the screen just like the screenshots given.
you can do one thing that just wrap floating action button to AnimatedContainer
AlignmentDirectional _ironManAlignment = AlignmentDirectional.bottomCenter;
...
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
floatingActionButton: AnimatedContainer(
duration: Duration(seconds: 2),
alignment: _ironManAlignment,
child: FloatingActionButton(
onPressed: () {
_flyIronMan();
},
child: Icon(Icons.add),
),
),
like this
when you press button then call this method
void _flyIronMan() {
setState(() {
_ironManAlignment =
AlignmentDirectional(0.0, -0.8); //AlignmentDirectional(0.0,-0.7);
});
}
Just wrap buttons on each page with Hero widget, like that:
Hero(
tag: 'fab',
child: FloatingActionButton()
);
With the design you want to achieve, I suggest you to use sliding_up_panel instead of pushing new screen.
It has a parameter collapsed, in which you can put FloatingActionButton to expand panel on tap, and show the same button inside the expanded panel. Just set panel non-draggable, and it won't expand on swipe.
Please read it's documentation carefully, I'm sure you can achieve the effect you want with this widget.