How to extends properties of a widget and use in custom widget in flutter [closed] - react-native

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
How can I create widget that contain all properties of a another widget.
e.g. in react-native I can create interface that extends ButtonProps;
Here I can pass all ButtonProps properties to my ButtonComponent.
interface ButtonComponentProps extends ButtonProps {
isError: boolean;
}
function ButtonComponent({isError, ...props}: ButtonComponentProps) {
return (
<Button color={isError ? 'red' : 'blue'} {...props} />
)
}
How can I do something like this in flutter?
e.g. I want to create screen_wrapper widget that contains all properties of scaffold class:
class ScreenContainer extends StatelessWidget {
final Widget child;
final Color statusbarcolor;
final Brightness statusBarIconBrightness;
final bool safeArea;
final Color bgColor;
final bool withScaffold;
final bool loading;
ScreenContainer({
#required this.child,
this.withScaffold = true,
this.statusbarcolor,
this.statusBarIconBrightness,
this.safeArea = true,
this.loading = false,
this.bgColor = Colors.white,
});
#override
Widget build(BuildContext context) {
final Widget widget = TabDetector(
child: Container(
width: MediaQuery.of(context).size.width,
padding: EdgeInsets.only(top: safeArea ? MediaQuery.of(context).padding.top : 0),
child: child,
),
);
return AnnotatedRegion<SystemUiOverlayStyle>(
value: SystemUiOverlayStyle(
statusBarColor: statusbarcolor ?? Colors.white,
statusBarIconBrightness: statusBarIconBrightness ?? Brightness.light,
),
child: Scaffold(
backgroundColor: Colors.white,
body: widget,
// pass other scaffold properties here
),
);
}
}
and then use it:
ScreenContainer(
appbar: Appbar(),
child: Text('hello'),
);

If I understand your situation right, then what you can do is, make a StatlessWidget having all the properties, and then just accept the child to be passed
class YourClass extends StatelessWidget{
final Widget child;
YourClass({Key key, this.child}): super(key:key);
#override
Widget build(BuildContext context) {
return Scaffold(
// have all your properties and then the child
body: this.child
);
}
}
Use it like this
class AnotherClass extends StatelessWidget{
#override
Widget build(BuildContext context) {
// using your class
return YourClass(
child: your_widget
);
}
}
The above will have all the properties of the YourClass, then widget will be passed from AnotherClass. You can use YourClass anywhere, where you want the Scaffold properties like this only.

Related

Flutter independencies

import 'package:flutter/material.dart';
import 'package:english_words/english_words.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
final wordPair = WordPair.random();
return MaterialApp(
theme: ThemeData(primaryColor: Colors.purple[900]),
home: Scaffold(
appBar: AppBar(title: Text('WorldPair Generator')),
`enter code here`body: Center(child: Text(wordPair.asPascaLCase))));
ERROR MESSAGE:
lib/main.dart:10:22: Error: The getter 'WordPair' isn't defined for the class 'MyApp'.
'MyApp' is from 'package:api_app/main.dart' ('lib/main.dart').
Try correcting the name to the name of an existing getter, or defining a getter or field named 'WordPair'.
final wordPair = WordPair.random();
^^^^^^^^
You can in pubspec.yaml add english_words: any in dependencies and click Pub get
See picture below
the author of english_words has actually turned off that command, so it doesnt work, But if you want to generate some random words, you can use the SuperHeroName Generator from pub.dev

ViewManager receiveCommand is deprecated?

I've recently noticed in the react-native source code that the following method:
public void receiveCommand(#NonNull T root, int commandId, #Nullable ReadableArray args)
of the ViewManager class is marked as deprecated. Therefore, I tried to replace it with an overloaded version that is not marked as deprecated:
public void receiveCommand(#NonNull T root, String commandId, #Nullable ReadableArray args)
but this one never gets invoked. I imagine I also might need to change some other methods, but I cannot find any information what else has to be done, there is no migration guide that I could follow.
Does anyone know how to properly use the new, non-deprecated receiveCommand method?
The source code of the ViewManager can be found here:
https://github.com/facebook/react-native/blob/master/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManager.java
The new, non-deprecated version of receiveCommand will get called if a String is sent as the second argument of the dispatchViewManagerCommand from your React Native code. There is no need to override getCommandsMap() anymore.
Example:
CustomViewManager.kt (In Kotlin, should be easy to convert to Java)
class CustomViewManager : SimpleViewManager<CustomView>() {
...
override fun createViewInstance( context: ThemedReactContext): CustomView {
// code to instantiate your view
}
...
override fun getName(): String {
return "CustomView"
}
...
override fun receiveCommand(view: CustomView, commandId: String, args: ReadableArray?) {
when (commandId) {
"doSomething" -> doSomething()
}
}
MyComponent.js
import { View, requireNativeComponent, UIManager, findNodeHandle } from 'react-native';
...
const CustomView = requireNativeComponent('CustomView');
...
export default class MyComponent extends Component {
...
onDoSomething = async () => {
UIManager.dispatchViewManagerCommand(
findNodeHandle(this.customView),
'doSomething',
undefined,
);
};
...
render() {
return (
<View>
<CustomView
ref={(component) => {
this.customView = component;
}}
/>
</View>
);
}
}

TypeScript: convert typeof back to instance

I have function that creates instances of given class and I don't how to tell TypeScript that:
function builder returns instances of class passed in first argument
class A extends HTMLElement {
color: 'white'
}
function builder<T extends typeof HTMLElement>(classParam: T) {
let instance = new classParam()
return instance
}
let instance = builder(A)
instance.color = 'black'
// Property 'color' does not exist on type 'HTMLElement'
Is it possible without using type assertion?
I've fixed and explained the problems:
class A extends HTMLElement {
color: string = 'white' // you gave it the type "white",
// but I assume you need the value "white" (and type `string`)
}
function builder<T extends HTMLElement>(classParam: { new(): T }) : T {
// previous line:
// - `typeof` in the generic constraint is not valid
// - the parameter could not be of type `T`, because you would not be
// able to use `new`. It's now a parameter which has a constructor
// which creates a `T`
// - we are now returning `T`, instead of (implicit) `any`
let instance = new classParam()
return instance
}
let instance = builder(A)
instance.color = 'black'
Link to playground

Call a default constructor from another one in Kotlin

In Kotlin, when a class has multiple constructors how can we call the designated (coming from iOS world I could not find a better name) constructor from within another constructor.
Let me show you an example
final class LoadingButton: LinearLayout {
var text:String? = null
constructor(context: Context, text: String) : this(context) {
this.text = text
}
constructor(context: Context) : super(context) {
val t = this.text
this.view {
button(t) { /* ... */}
}
}
}
Here if I do loadingButton("TEST", {}) that string is not propagated to the button because this(context) is called before the code inside the convenience constructor (sorry again :).
Can that be solved in Kotlin ? Something like
constructor(context: Context, text: String) {
this.text = text
this(context)
}
EDIT
Just to clarify the idea since it's been asked, the idea is to write something like this in an activity :
onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
verticalLayout {
loadingButton("Some text")
//or
loadingButton() { this.text = "Some text"}
}
This is obviously not that much useful but you get the idea. The text property can be known at construction or later on.
This is especially not useful since Kotlin has default values for parameters but I am studying the language and ran into this problem.
EDIT 2
Another clarification is that I'm using Anko for the layout, so the loadingButton methods look like this:
inline fun ViewManager.loadingButton() = loadingButton { }
inline fun ViewManager.loadingButton(init: LoadingButton.() -> Unit) = ankoView({ LoadingButton(it) }, init)
inline fun ViewManager.loadingButton(text: String, init: LoadingButton.() -> Unit) = ankoView({ LoadingButton(it, text) }, init)
The code with a post-call to a constructor cannot exist on JVM since you MUST call super(...) before you do anything with the class itself. Think of it as if the super class contained a private field, you would have to initialise it before you can use it.
This is usually not a problem since you can call the constructors the other way around:
constructor(context: Context, text: String?) : super(context) {
this.text = text
this.view {
button(text) { /* ... */}
}
}
constructor(context: Context) : this(context, null)
constructor(context: Context, text: String) : this(context, text)
The code above does roughly the same as a default argument:
constructor(context: Context, text: String? = null) : super(context) {
this.text = text
this.view {
button(text) { /* ... */}
}
}
To make this code idiomatic (and concise), use a primary constructor:
class LoadingButton(context: Context, val text: String? = null): LinearLayout(context) {
init {
this.view {
button(text) { /* ... */}
}
}
}
The terminology goes as following: designated - primary, convenience - secondary
See Classes and Inheritance - Kotlin Programming Language for more details.

Dynamically load/assign objects in QML

I've just started with QML game development using V-Play and coming from java, I stil have problems understanding some basics.
I know how I'd do it in Java, but don't know how it works in QML, so I'll explain it in Java terms:
I have a "base class" with some properties and methods. Then I have modules extending this base class with more specific features. (Like "class Module1 extends BaseModule")
Then I have an object ("ModuleContainer") that contains a Module, but I don't know which one - it's loaded dynamically at runtime. Thus, in Java i'd create a new object like "BaseModule someModule = new Module1()", and can later access it and also replace it (like "someModule = new Module2()").
How could I do that in QML?
I've tried properties, but I haven't found a way to create a new object and then use it. Dynamic creation of objects with an entityManager doesn't quit seem to work for this either.
I played around with components a bit and together with a Loader, it's pretty much exactly what I wanted.
Here's my code if anyone else needs something like this:
Basically, I create a baseclass (BaseModule), create two Modules that extend that class (java terms).
In a new class (ModuleSlot), I create two components containing a Module each, that can be dynamically loaded and replaced in the Main code.
Important parts
//define a component and make it accessible from the outside
property Component cmodule1: module1
Component {
id: module1
Module1 {
}
}
//define a component to hold the component to use (for easier changing)
property Component dynamicModule: dynamicModuleHolder.cmodule1
ModuleSlot {
id:dynamicModuleHolder
}
//the magic happens here: the defined component is loaded dynamically on runtime,
when changed, the old one is removed and the new one loaded
Loader {
sourceComponent:dynamicModule
}
Full Code
Main.qml:
GameWindow {
id: gameWindow
//licenseKey: "<generate one from http://v-play.net/licenseKey>"
activeScene: scene
width: 640
height: 960
property Component dynamicModule: dynamicModuleHolder.cmodule1
property int activeElement: 1
Scene {
id: scene
width: 640
height: 960
Loader{
sourceComponent:dynamicModule
}
ModuleSlot {
id:dynamicModuleHolder
}
MouseArea {
anchors.fill: parent
onClicked: {
if(activeElement == 1) {
dynamicModule = dynamicModuleHolder.cmodule2
activeElement = 2
} else {
dynamicModule = dynamicModuleHolder.cmodule1
activeElement = 1
}
}
}
}
}
BaseModule.qml:
Item {
property int someAttribute: 0
}
Module1.qml/Module2.qml (Module2 only has a different Rectangle)
BaseModule {
someAttribute: 5 // just to show that Module1 inherits from BaseModule
Rectangle {
color: "red"
width: 50
height: 50
x: 200
y: 200
}
}
ModuleSlot
Item {
property Component cmodule1: module1
property Component cmodule2: module2
QtObject {
id: internalSettings
property color color: "green"
}
Component {
id: module1
Module1 {
}
}
Component {
id: module2
Module2 {
}
}
}