Sizing a dynamically sized Widget by a factor - user-interface

I'm trying to set the heightFactor of a dynamically sized Widget (for animation purposes), in this case a Text:
Stack(
children: <Widget>[
Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
FractionallySizedBox(
heightFactor: 0.5,
child: Text(
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
),
),
],
),
Positioned.fill(
child: Center(
child: Text(
"Lorem ipsum".toUpperCase(),
),
),
),
],
);
that however results in the following exception:
I/flutter ( 7123): ══╡ EXCEPTION CAUGHT BY RENDERING LIBRARY ╞═════════════════════════════════════════════════════════
I/flutter ( 7123): The following assertion was thrown during performLayout():
I/flutter ( 7123): BoxConstraints forces an infinite height.
I/flutter ( 7123): These invalid constraints were provided to RenderParagraph's layout() function by the following
I/flutter ( 7123): function, which probably computed the invalid constraints in question:
I/flutter ( 7123): RenderFractionallySizedOverflowBox.performLayout
I/flutter ( 7123): (package:flutter/src/rendering/shifted_box.dart:909:13)
I/flutter ( 7123): The offending constraints were:
I/flutter ( 7123): BoxConstraints(w=272.0, h=Infinity)
And wrapping the Text in either LimitedBox or ConstrainedBox seems to only change what the invalid constraints were provided to in the error message.
Nor does adding MainAxisSize.min to Column.mainAxisSize seem to make a difference.
Is there a way to accomplish this that avoids the error?

A FractionallySizedBox sizes itself to its parent. Because you're using a column within a stack it doesn't really have a limit on infinite height. Since infinity / 2 == infinity your text therefore also has an infinite height.
If you switch to using an align, you can size your object to the text rather than the parent.

Related

Correct YAML syntax from frontmatter

I need to achieve this frontmatter:
services:
- service:
serviceName: Service 1
serviceDesc: Blah
- service:
serviceName: Service 2
serviceDesc: Blah
- service:
serviceName: Service 3
serviceDesc: Blah
Here is my current Yaml syntax:
services:
service:
- serviceName: Water Treatment
serviceDesc: Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua.
- serviceName: Environmental Services
serviceDesc: Lorem ipsum dolor sit amet, consectetur adipiscing eliy, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua.
I am using Netlify CMS to create this but I cannot find a solution to get an individual service to use with Nunjucks.
Any help would be amazing.
Seeing your config.yml file would help, but from the look of your current output, I will assume that it looks something like this:
- label: 'Services'
name: 'services'
widget: 'object'
fields:
- label: 'Service'
name: 'service'
widget: 'list'
fields:
- { label: 'Name', name: 'serviceName', widget: string }
- { label: 'Description', name: 'serviceDesc', widget: text }
In you case, you want the service node to be one level lower, wrapping each list element, so you should be able to just switch the position of your object and list widgets like so:
- label: 'Services'
name: 'services'
widget: 'list'
fields:
- label: 'Service'
name: 'service'
widget: 'object'
fields:
- { label: 'Name', name: 'serviceName', widget: string }
- { label: 'Description', name: 'serviceDesc', widget: text }

react-navigation BottomTabNavigator VERY slow on some Android devices

I've got a minimal test ReactNative test in Expo running. 2 screens, both just have Text within a View.
This is run on a MBP, and tested on my Android device (Note10+) via QR code.
It is not just slow, it's unresponsive most of the time, when it does navigate to a tab on click then it's either instant (rarely) or takes 5-10 seconds. But usually nothing happens.
There are no errors being shown, replacing the same code with a Stack or Drawer works fine.
2 basic screens:
function StackScreenA0({navigation}) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Test stack 0</Text>
<Button title="goto 1" onPress={() => navigation.navigate('Screen A1')} />
</View>
);
}
function StackScreenA1({navigation}) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Test stack 0</Text>
<Button title="goto 0" onPress={() => navigation.navigate('Screen A0')} />
</View>
);
}
App code (minus imports):
const Tab = createBottomTabNavigator();
function App() {
return (
<NavigationContainer>
<Tab.Navigator initialRoutName='Screen A0'>
<Tab.Screen name="Screen A0" component={StackScreenA0} />
<Tab.Screen name="Screen A1" component={StackScreenA1} />
</Tab.Navigator>
</NavigationContainer>
);
}
export default App;
I've never used Expo before but I can't imagine this is normal behaviour but cannot see a reason for it working so badly.
EDIT: I've found other devices to test and tabs are fine on iPad4, Galaxy9, but seriously bad on Note10+.
Rich

GraphQL returning no errors but undefined

Have been searching for a while. I am using Gatsby and I have no errors in the console or terminal but values are undefined. Could it be because of the second "data" under "articles"?
GraphiQL Query:
Query/Component Code:
import React, { Component } from 'react'
import { graphql } from 'gatsby'
// This query is executed at build time by Gatsby.
export const GatsbyQuery = graphql`
{
umdHub {
articles {
data {
title
}
}
}
}
`
class ClientFetchingExample extends Component {
render() {
const {
umdHub: { articles },
} = this.props.data
console.log(articles.title)
return (
<div style={{ textAlign: 'center', width: '600px', margin: '50px auto' }}>
<h1>{articles.title} - Is the title of the article</h1>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
</div>
)
}
}
export default ClientFetchingExample
You already halfway there just small changes
const {
umdHub: { articles },
} = this.props.data
Now you have this articles object like this
articles: {
data: [
{
title: 'Learning to Listen'
},
{
title: 'Second Title'
}
...
]
}
Now you need to loop over data
import _ from 'lodash'
const data = _.get(articles, 'data', [])
_.map(data, title => {
console.log({ title })
})
If you want to only first title then
const title = _.get(articles, 'data[0].title', 'default value or blank string')
Here lodash is A modern JavaScript utility library delivering modularity, performance & extras.

Not able to validate mandatory input field widgets in flutter/dart

I am trying to validate my user input which contains two input fields "title" and "description" after click on floating action button but I am getting an error when I do that.
notes_detail_widget.dart
class NoteDetailsWidgetState extends State<NoteDetailsWidget> {
final _formKey = new GlobalKey<FormState>();
String _title;
String _description;
_submit() {
if (_formKey.currentState.validate()) {
_formKey.currentState.save();
}
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("Edit note data"),
),
body: new Form(
child: new Container(
margin: new EdgeInsets.all(16.0),
child: new Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
new Container(
child: new TextFormField(
decoration: new InputDecoration(
labelText: "Title",
border: InputBorder.none,
),
validator: (val) =>
val.isNotEmpty ? null : "Title must not be empty",
onSaved: (val) => _title = val),
),
new Container(
child: new Divider(
color: Colors.black,
)),
new TextFormField(
decoration: new InputDecoration(
labelText: "Description",
border: InputBorder.none,
),
keyboardType: TextInputType.multiline,
maxLines: 3,
validator: (val) =>
val.isNotEmpty ? null : "Description must not be empty",
onSaved: (val) => _description = val,
)
])),
),
floatingActionButton: new FloatingActionButton(
onPressed: () => _submit(), child: new Icon(Icons.check)),
);
}
}
Error Log:
I/flutter ( 8055): ══╡ EXCEPTION CAUGHT BY GESTURE ╞═══════════════════════════════════════════════════════════════════
I/flutter ( 8055): The following NoSuchMethodError was thrown while handling a gesture:
I/flutter ( 8055): The method 'validate' was called on null.
I/flutter ( 8055): Receiver: null
I/flutter ( 8055): Tried calling: validate()
I/flutter ( 8055):
I/flutter ( 8055): When the exception was thrown, this was the stack:
I/flutter ( 8055): #0 Object.noSuchMethod (dart:core/runtime/libobject_patch.dart:50:5)
I/flutter ( 8055): #1 NoteDetailsWidgetState._submit (package:notes_crud_app/note_details_widget.dart:16:31)
I/flutter ( 8055): #2 NoteDetailsWidgetState.build.<anonymous closure> (package:notes_crud_app/note_details_widget.dart:61:28)
I/flutter ( 8055): #3 _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:507:14)
I/flutter ( 8055): #4 _InkResponseState.build.<anonymous closure> (package:flutter/src/material/ink_well.dart:562:30)
I/flutter ( 8055): #5 GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:102:24)
I/flutter ( 8055): #6 TapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:242:9)
I/flutter ( 8055): #7 TapGestureRecognizer.handlePrimaryPointer (package:flutter/src/gestures/tap.dart:175:7)
I/flutter ( 8055): #8 PrimaryPointerGestureRecognizer.handleEvent (package:flutter/src/gestures/recognizer.dart:315:9)
I/flutter ( 8055): #9 PointerRouter._dispatch (package:flutter/src/gestures/pointer_router.dart:73:12)
I/flutter ( 8055): #10 PointerRouter.route (package:flutter/src/gestures/pointer_router.dart:101:11)
I/flutter ( 8055): #11 _WidgetsFlutterBinding&BindingBase&GestureBinding.handleEvent (package:flutter/src/gestures/binding.dart:180:19)
I/flutter ( 8055): #12 _WidgetsFlutterBinding&BindingBase&GestureBinding.dispatchEvent (package:flutter/src/gestures/binding.dart:158:22)
I/flutter ( 8055): #13 _WidgetsFlutterBinding&BindingBase&GestureBinding._handlePointerEvent (package:flutter/src/gestures/binding.dart:138:7)
I/flutter ( 8055): #14 _WidgetsFlutterBinding&BindingBase&GestureBinding._flushPointerEventQueue (package:flutter/src/gestures/binding.dart:101:7)
I/flutter ( 8055): #15 _WidgetsFlutterBinding&BindingBase&GestureBinding._handlePointerDataPacket (package:flutter/src/gestures/binding.dart:85:7)
I/flutter ( 8055): #16 _invoke1 (dart:ui/hooks.dart:168:13)
I/flutter ( 8055): #17 _dispatchPointerDataPacket (dart:ui/hooks.dart:122:5)
I am quite new to both Dart and Flutter. Please guide.
you didn't add the form key inside the form
body:new Form(
key: _formKey,
child: new Column(
//rest of the code
)
),

trying to animate a constraint in swift

I have a UITextField that I want to enlarge its width when tapped on. I set up the constraints and made sure the constraint on the left has the lower priority then the one that I am trying to animate on the right side.
Here is the code that I am trying to use.
// move the input box
UIView.animateWithDuration(10.5, animations: {
self.nameInputConstraint.constant = 8
}, completion: {
(value: Bool) in
println(">>> move const")
})
This works, but it seems to just happen instantly and there doesn't seem to be any movement. I tried to set it 10 seconds to make sure I wasn't missing anything, but I got the same results.
nameInputConstraint is the name of the constraint that I control dragged to connect into my class from IB.
You need to first change the constraint and then animate the update.
This should be in the superview.
self.nameInputConstraint.constant = 8
Swift 2
UIView.animateWithDuration(0.5) {
self.view.layoutIfNeeded()
}
Swift 3, 4, 5
UIView.animate(withDuration: 0.5) {
self.view.layoutIfNeeded()
}
SWIFT 4 and above:
self.mConstraint.constant = 100.0
UIView.animate(withDuration: 0.3) {
self.view.layoutIfNeeded()
}
Example with completion:
self.mConstraint.constant = 100
UIView.animate(withDuration: 0.3, animations: {
self.view.layoutIfNeeded()
}, completion: {res in
//Do something
})
It's very important to point out that view.layoutIfNeeded() applies to the view subviews only.
Therefore to animate the view constraint, it is important to call it on the view-to-animate superview as follows:
topConstraint.constant = heightShift
UIView.animate(withDuration: 0.3) {
// request layout on the *superview*
self.view.superview?.layoutIfNeeded()
}
An example for a simple layout as follows:
class MyClass {
/// Container view
let container = UIView()
/// View attached to container
let view = UIView()
/// Top constraint to animate
var topConstraint = NSLayoutConstraint()
/// Create the UI hierarchy and constraints
func createUI() {
container.addSubview(view)
// Create the top constraint
topConstraint = view.topAnchor.constraint(equalTo: container.topAnchor, constant: 0)
view.translatesAutoresizingMaskIntoConstraints = false
// Activate constaint(s)
NSLayoutConstraint.activate([
topConstraint,
])
}
/// Update view constraint with animation
func updateConstraint(heightShift: CGFloat) {
topConstraint.constant = heightShift
UIView.animate(withDuration: 0.3) {
// request layout on the *superview*
self.view.superview?.layoutIfNeeded()
}
}
}
With Swift 5 and iOS 12.3, according to your needs, you may choose one of the 3 following ways in order to solve your problem.
#1. Using UIView's animate(withDuration:animations:) class method
animate(withDuration:animations:) has the following declaration:
Animate changes to one or more views using the specified duration.
class func animate(withDuration duration: TimeInterval, animations: #escaping () -> Void)
The Playground code below shows a possible implementation of animate(withDuration:animations:) in order to animate an Auto Layout constraint's constant change.
import UIKit
import PlaygroundSupport
class ViewController: UIViewController {
let textView = UITextView()
lazy var heightConstraint = textView.heightAnchor.constraint(equalToConstant: 50)
override func viewDidLoad() {
view.backgroundColor = .white
view.addSubview(textView)
textView.backgroundColor = .orange
textView.isEditable = false
textView.text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
textView.translatesAutoresizingMaskIntoConstraints = false
textView.topAnchor.constraint(equalToSystemSpacingBelow: view.layoutMarginsGuide.topAnchor, multiplier: 1).isActive = true
textView.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor).isActive = true
textView.trailingAnchor.constraint(equalTo: view.layoutMarginsGuide.trailingAnchor).isActive = true
heightConstraint.isActive = true
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(doIt(_:)))
textView.addGestureRecognizer(tapGesture)
}
#objc func doIt(_ sender: UITapGestureRecognizer) {
heightConstraint.constant = heightConstraint.constant == 50 ? 150 : 50
UIView.animate(withDuration: 2) {
self.view.layoutIfNeeded()
}
}
}
PlaygroundPage.current.liveView = ViewController()
#2. Using UIViewPropertyAnimator's init(duration:curve:animations:) initialiser and startAnimation() method
init(duration:curve:animations:) has the following declaration:
Initializes the animator with a built-in UIKit timing curve.
convenience init(duration: TimeInterval, curve: UIViewAnimationCurve, animations: (() -> Void)? = nil)
The Playground code below shows a possible implementation of init(duration:curve:animations:) and startAnimation() in order to animate an Auto Layout constraint's constant change.
import UIKit
import PlaygroundSupport
class ViewController: UIViewController {
let textView = UITextView()
lazy var heightConstraint = textView.heightAnchor.constraint(equalToConstant: 50)
override func viewDidLoad() {
view.backgroundColor = .white
view.addSubview(textView)
textView.backgroundColor = .orange
textView.isEditable = false
textView.text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
textView.translatesAutoresizingMaskIntoConstraints = false
textView.topAnchor.constraint(equalToSystemSpacingBelow: view.layoutMarginsGuide.topAnchor, multiplier: 1).isActive = true
textView.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor).isActive = true
textView.trailingAnchor.constraint(equalTo: view.layoutMarginsGuide.trailingAnchor).isActive = true
heightConstraint.isActive = true
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(doIt(_:)))
textView.addGestureRecognizer(tapGesture)
}
#objc func doIt(_ sender: UITapGestureRecognizer) {
heightConstraint.constant = heightConstraint.constant == 50 ? 150 : 50
let animator = UIViewPropertyAnimator(duration: 2, curve: .linear, animations: {
self.view.layoutIfNeeded()
})
animator.startAnimation()
}
}
PlaygroundPage.current.liveView = ViewController()
#3. Using UIViewPropertyAnimator's runningPropertyAnimator(withDuration:delay:options:animations:completion:) class method
runningPropertyAnimator(withDuration:delay:options:animations:completion:) has the following declaration:
Creates and returns an animator object that begins running its animations immediately.
class func runningPropertyAnimator(withDuration duration: TimeInterval, delay: TimeInterval, options: UIViewAnimationOptions = [], animations: #escaping () -> Void, completion: ((UIViewAnimatingPosition) -> Void)? = nil) -> Self
The Playground code below shows a possible implementation of runningPropertyAnimator(withDuration:delay:options:animations:completion:) in order to animate an Auto Layout constraint's constant change.
import UIKit
import PlaygroundSupport
class ViewController: UIViewController {
let textView = UITextView()
lazy var heightConstraint = textView.heightAnchor.constraint(equalToConstant: 50)
override func viewDidLoad() {
view.backgroundColor = .white
view.addSubview(textView)
textView.backgroundColor = .orange
textView.isEditable = false
textView.text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
textView.translatesAutoresizingMaskIntoConstraints = false
textView.topAnchor.constraint(equalToSystemSpacingBelow: view.layoutMarginsGuide.topAnchor, multiplier: 1).isActive = true
textView.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor).isActive = true
textView.trailingAnchor.constraint(equalTo: view.layoutMarginsGuide.trailingAnchor).isActive = true
heightConstraint.isActive = true
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(doIt(_:)))
textView.addGestureRecognizer(tapGesture)
}
#objc func doIt(_ sender: UITapGestureRecognizer) {
heightConstraint.constant = heightConstraint.constant == 50 ? 150 : 50
UIViewPropertyAnimator.runningPropertyAnimator(withDuration: 2, delay: 0, options: [], animations: {
self.view.layoutIfNeeded()
})
}
}
PlaygroundPage.current.liveView = ViewController()
In my case, I only updated the custom view.
// DO NOT LIKE THIS
customView.layoutIfNeeded() // Change to view.layoutIfNeeded()
UIView.animate(withDuration: 0.5) {
customViewConstraint.constant = 100.0
customView.layoutIfNeeded() // Change to view.layoutIfNeeded()
}
I would like to share my solution, in my not working case my constraint designed like below
view1WidthLayout = NSLayoutConstraint(item: view1,
attribute: .width,
relatedBy: .equal,
toItem: nil,
attribute: .width,
multiplier: 1,
constant: 20)
and whenever I tried to set constant before the animation like
view1WidthLayout.constant += 20
it set immediately so it did not work for me.
I change the definition of the constraint property like
view1WidthLayout = view1.widthAnchor.constraint(equalToConstant: 20)
then it worked for myself
Watch this.
The video says that you need to just add self.view.layoutIfNeeded() like the following:
UIView.animate(withDuration: 1.0, animations: {
self.centerX.constant -= 75
self.view.layoutIfNeeded()
}, completion: nil)

Resources