i have an issue with ordering, combining and positioning of my solid shapes and text
the task is simple enough, but while im completely newbie in swfitui i cannot do it for my self
task: place solid shapes with zstack relative by their parrent using coordinates (including text of each shape) and apply isometric/perpective modifier
i will be glad for explanations and hints
this is what i have done for now
works without modifiers
and no with isometric modifier
struct ContentView: View {
#ObservedObject var datas = ReadData()
//MagnificationState
//DragState
//#GestureState
//#State viewMagnificationState
//#GestureState
//#State viewDragState
//magnificationScale
//translationOffset
//#State popoverState
//#State selectedShape
var body: some View {
//magnificationGesture
//dragGesture
//magnificationGesture.simultaneously
GeometryReader { geometry in
ZStack(alignment: .topLeading) {
MainShape(showingPopover: $popoverState,
setCurrentShape: $selectedShape,
alldatas: datas.pokedex)
}
.scaleEffect(magnificationScale)
.offset(translationOffset)
//.position(x: geometry.size.width / 2, y: geometry.size.height / 2)
//.gesture(both)
//popover
}
.edgesIgnoringSafeArea(.all)
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
struct MainShape: View {
let alldatas: [PokedexElement]
var body: some View {
ForEach(alldatas, id: \.id) { shape in
ZStack(alignment: .topLeading) {
Text(shape.metaProperties.name)
.font(.system(size: 20))
.zIndex(2)
.offset(x: shape.metaProperties.offset.x, y: shape.metaProperties.offset.y)
Rectangle()
.cornerRadius(shape.id == 1 ? 55 : 10)
.foregroundColor(chooseColor(shape.metaProperties.color))
.offset(x: shape.metaProperties.offset.x, y: shape.metaProperties.offset.y)
.frame(
width: shape.metaProperties.size.width,
height: shape.metaProperties.size.height
)
.isometric()
.zIndex(1)
.onTapGesture {
self.showingPopover = true
self.setCurrentShape = shape.id
}
}
}
}
}
data:
[
{
"id": 1,
"parentId": 0,
"baseProperties": {
"name": "",
"descr": "",
"contacts": ""
},
"metaProperties": {
"name": "root",
"status": true,
"type": "plain",
"size": {
"width": 350,
"height": 350
},
"offset": {
"x": 0,
"y": 0
},
"color": "blue"
}
},
{
"id": 2,
"parentId": 1,
"baseProperties": {
"name": "object 1",
"descr": "",
"contacts": ""
},
"metaProperties": {
"name": "child 1",
"status": true,
"type": "imobject",
"size": {
"width": 50,
"height": 50
},
"offset": {
"x": 50,
"y": 50
},
"color": "red"
}
},
{
"id": 3,
"parentId": 1,
"baseProperties": {
"name": "object 1",
"descr": "",
"contacts": ""
},
"metaProperties": {
"name": "child 2",
"status": true,
"type": "imobject",
"size": {
"width": 100,
"height": 50
},
"offset": {
"x": 100,
"y": 50
},
"color": "green"
}
}
]
and modifiers…
extension View {
func chooseColor(_ name: String) -> Color {
switch name {
case "red":
return Color.red
case "blue":
return Color.blue
case "brown":
return Color.brown
case "green":
return Color.green
case "yellow":
return Color.yellow
case "white":
return Color.white
default :
return Color.black
}
}
func perspective() -> some View {
self
.rotation3DEffect(.degrees(45), axis: (x: 1, y: 0, z: 0))
}
func isometric() -> some View {
self
.rotationEffect(Angle.init(degrees: 45))
.scaleEffect(y: 0.5)
}
}
task was easy, instead of using regular solid shapes with "magic methods from black box" do it all manually
convert decart to iso and place it whatever you want together with text or anything else and offset will be fine
Container Size depends on the widget's child length
I want all things in the mobile screen height not the inner child scroll or outer
I expected output like below -
what I am getting -
import 'package:flutter/material.dart';
class ExpandableContainer extends StatefulWidget {
const ExpandableContainer({Key? key}) : super(key: key);
#override
State<ExpandableContainer> createState() => _ExpandableContainerState();
}
class _ExpandableContainerState extends State<ExpandableContainer> {
int selectedIndex = -1;
List dataList = [
{
"title": "Title 1",
"items": [
'Item 1',
'Item 2',
'Item 3',
'Item 4',
],
},
{
"title": "Title 2",
"items": [
"Item 1",
"Item 2",
"Item 3",
"Item 4",
"Item 5",
"Item 6",
"Item 7",
"Item 8",
],
},
{
"title": "Title 3",
"items": [
"Item 1",
"Item 2",
"Item 3",
"Item 4",
],
},
{
"title": "Title 4",
"items": [
"Item 1",
"Item 2",
"Item 3",
"Item 4",
"Item 5",
"Item 6",
"Item 7",
"Item 8",
"Item 9",
"Item 10",
],
},
{
"title": "Title 5",
"items": [
"Item 1",
"Item 2",
"Item 3",
"Item 4",
"Item 5",
"Item 6",
"Item 7",
],
},
];
#override
Widget build(BuildContext context) {
final Size size = MediaQuery.of(context).size;
return Scaffold(
backgroundColor: Colors.white,
body: SizedBox(
height: size.height,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: List.generate(
dataList.length,
(index) => GestureDetector(
onTap: () => setState(() {
selectedIndex = index;
}),
child: Container(
height: size.height / dataList.length,
width: size.width,
padding: const EdgeInsets.fromLTRB(32.0, 16.0, 0.0, 16.0),
// alignment: Alignment.center,
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(width: 8.0, color: Colors.grey),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
dataList[index]["title"].toUpperCase(),
style: const TextStyle(
fontSize: 38.0,
color: Colors.black,
fontWeight: FontWeight.w900,
letterSpacing: -2.0,
),
),
for (var item in dataList[index]["items"])
Text(
selectedIndex == index ? item : "",
style: TextStyle(
fontSize: 20.0,
color: Colors.black,
height: selectedIndex == index ? 1.5 : 0.0,
),
),
],
),
),
),
),
),
),
);
}
}
List<String> category = [
"HealthCare",
"Food & Drink",
"Beauty",
"Baby & kids",
"Homeware"
];
List<Color> color = [
Colors.lightBlueAccent,
Colors.green.shade700,
Colors.pinkAccent.shade100,
Colors.blueAccent,
Colors.amber,
];
List<Color> textColor = [
Colors.blueAccent.shade700,
Colors.amber,
Colors.pinkAccent.shade700,
Colors.pinkAccent.shade100,
Colors.white,
];
int? selectedIndex;
List<dynamic> dataList = [
{
"title": "Title 1",
"items": [
'Item 1',
'Item 2',
'Item 3',
'Item 4',
],
},
{
"title": "Title 2",
"items": [
"Item 1",
"Item 2",
"Item 3",
"Item 4",
"Item 5",
"Item 6",
"Item 7",
"Item 8",
],
},
{
"title": "Title 3",
"items": [
"Item 1",
"Item 2",
"Item 3",
"Item 4",
],
},
{
"title": "Title 4",
"items": [
"Item 1",
"Item 2",
"Item 3",
"Item 4",
"Item 5",
"Item 6",
"Item 7",
"Item 8",
"Item 9",
"Item 10",
],
},
{
"title": "Title 5",
"items": [
"Item 1",
"Item 2",
"Item 3",
"Item 4",
"Item 5",
"Item 6",
"Item 7",
],
},
];
Scaffold(
body: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisSize: MainAxisSize.max,
children: [
...category.map(
(index) => Expanded(
flex: selectedIndex==category.indexOf(index) ? (dataList[category.indexOf(index)]["items"].length/3).ceil(): 1,
child: GestureDetector(
onTap: () {
print(dataList[category.indexOf(index)]["items"].toString());
print("tap");
setState(() {
selectedIndex = category.indexOf(index);
});
},
child: Container(
color: color[category.indexOf(index)],
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
index.toUpperCase(),
style: TextStyle(
fontSize: 36,
fontWeight: FontWeight.bold,
color: textColor[category.indexOf(index)]),
),
selectedIndex == category.indexOf(index)
? Column(
children: [
...dataList[category.indexOf(index)]
["items"]
.map(
(e) => Text(e),
),
// ListTile(title:Text(dataList[category.indexOf(index)]["items"].toString()))
],
)
: SizedBox(),
],
),
),
),
),
),
),
],
),
);
Please use ExpansionTile for expansion
ExpansionTile(
iconColor:Colors.blue,
textColor:Colors.black,
title: Text('Privacy Policy',style: TextStyle(fontSize: 16)),
children: [
ListTile(
title: Text('item1',textAlign: justifyText,),
),
ListTile(
title: Text('item2',textAlign: justifyText,),
),
ListTile(
title: Text('item3',textAlign: justifyText,),
),
ListTile(
title: Text('item4',textAlign: justifyText,),
),
],
),
Try this you can test this on dartpad its so now the one is hindering the size was on the container so if you select a certain index make the container height to null so that it will wrap the results inside.
return Scaffold(
backgroundColor: Colors.white,
body: SizedBox(
child: ListView.builder(
shrinkWrap: true,
itemCount: dataList.length,
itemBuilder:(context,index)
=>GestureDetector(
onTap:(){
setState((){
selectedIndex = index;
print( dataList[index]['items'].map((e)=> e).toList());
});
},
child: Container(
height: selectedIndex == index ? null
: size.height / dataList.length,
width: size.width,
padding: const EdgeInsets.fromLTRB(32.0, 16.0, 0.0, 16.0),
// alignment: Alignment.center,
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(width: 8.0, color: Colors.grey),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
dataList[index]["title"].toUpperCase(),
style: const TextStyle(
fontSize: 38.0,
color: Colors.black,
fontWeight: FontWeight.w900,
letterSpacing: -2.0,
),
),
...dataList[index]['items'].map((e)=>
selectedIndex == index ?
Text(
e,
style: TextStyle(
fontSize: 20.0,
color: Colors.black,
height: selectedIndex == index ? 1.5 : 0.0,
) ,
) : Container(),).toList()
],
),
),
),
),
),
);
Solution No 1
To achieve this you can use ExpansionTile class,
This widget is typically used with ListView to create an "expand / collapse" list entry. When used with scrolling widgets like ListView, a unique PageStorageKey must be specified to enable the ExpansionTile to save and restore its expanded state when it is scrolled in and out of view.
this is the link about ExpansionTile
https://api.flutter.dev/flutter/material/ExpansionTile-class.html#:~:text=ExpansionTile%20class%20Null%20safety,expand%20%2F%20collapse%22%20list%20entry.
and this is the demo example link how to do it
https://rrtutors.com/tutorials/Expandable-Listview-Flutter-ExpansionTile
Solution No 2
Use ExpandableGroup
To achieve this you can use ExpandableGroup
this is the link about ExpandableGroup
https://pub.dev/packages/expandable_group
if you don't want to use plugin , just inspect this plugin code , it has simple logic
You can use expansion tile but if the existing expansion tile does not provide the view required for your project, you can create your own custom expansion tile widget.
Like
app_expansion_tile
You should use expansion tile, as far as i have saw in your image you don't want it to be scrollablle, what i suggest is to make a limitation on the expansiontile class or the child, then set restriction limit to with and height and make it be responsive.
I am trying to send horizontally scrollable carousel message on Facebook workplace platform using the generic template as described in the messenger platform documentation(Ref: https://developers.facebook.com/docs/messenger-platform/reference/template/generic)
The template that I am using looking something like this:
[
{
"text": "Hi!!!!"
},
{
"attachment": {
"type": "template",
"payload": {
"template_type": "generic",
"elements": [
{
"title": "Some Title 1",
"image_url": "some image url",
"buttons": [
{
"title": "button_title1",
"type": "postback",
"payload": "Title 1"
}
]
},
{
"title": "Some Title 2",
"image_url": "some image url",
"buttons": [
{
"title": "button_title2",
"type": "postback",
"payload": "Title 2"
}
]
},{
"title": "Some Title 3",
"image_url": "some image url",
"buttons": [
{
"title": "button_title3",
"type": "postback",
"payload": "Title 3"
}
]
},
]
}
}
}
]
Everything worked as I expected but, from the past 2 weeks or so, the order of carousel elements(cards in my case) isn't what I am expecting(i.e., Title1, Title2, Title3). The elements in the carousel are shown in a different order every time I use it. I just want to know if anyone else has the same issue or it has something to do with my code?
The code that I have used to send the message in the end is:
return new Promise((resolve, reject) => {
//(async ref:https://www.npmjs.com/package/async)
async.eachSeries(
//facebookMessages is the message template that I am using(posted above)
facebookMessages,
(msg, callback) => {
//sendFBSenderAction sends the message to FB using api(https://graph.facebook.com/v2.6/me/messages?access_token=<PAGE_ACCESS_TOKEN>)
this.sendFBSenderAction(sender, 'typing_on')
.then(() => this.sleep(this.messagesDelay))
.then(() => {
facebookMessages.attachment ? this.sendFbAttachment(msg) : this.sendFBMessage(sender, msg);
facebookMessages.attachment = false;
})
.then(() => callback())
.catch(callback);
},
err => {
if (err) {
console.error(err);
reject(err);
} else {
console.log('Messages sent');
resolve();
}
}
);
});
Looks like there’s already a current bug report for this - https://developers.facebook.com/support/bugs/260229951577494/
Subscribe to that, to be updated when the status of that bug report changes.
I have an Infragistics grid and am unable to delete a row when the primaryKey of the grid is of dataType string.
I can not set my primaryKey as dataType number because it is of this format: "KIT_001". Is there any clever way of using a delete button and being able to delete rows with this kind of data? Perhaps a way to set an incremented ID and use that for the delete button?
var dataSource = [
{"ProductID": "KIT_001", "Name": "Kit 1", "ProductNumber": "P4857"},
{"ProductID": "KIT_002", "Name": "Kit 2", "ProductNumber": "P4567"},
{"ProductID": "KIT_003", "Name": "Kit 3", "ProductNumber": "P4447"}
]
$(function () {
$("#grid").igGrid({
autoGenerateColumns: false,
width: "100%",
height: "500px",
columns: [
{ headerText: "Product ID", key: "ProductID", dataType: "string", width: "10%" },
{ headerText: "Product Name", key: "Name", dataType: "string", width: "30%" },
{ headerText: "Product Number", key: "ProductNumber", dataType: "string", width: "25%" },
{ headerText: "", key: "Delete", dataType: "string", width: "10%", unbound: true,
template: "<input type='button' onclick='deleteRow(${ProductID})' value='Delete' class='delete-button'/>"},
],
primaryKey: "ProductID",
dataSource: dataSource,
features: [
{
name: "Updating",
enableAddRow: false,
editMode: "row",
enableDeleteRow: false,
}
]
});
});
function deleteRow(rowId) { console.log('rowId ',rowId)
var grid = $("#grid").data("igGrid");
grid.dataSource.deleteRow(rowId);
grid.commit();
}
Enclose the key parameter in quotes in your template:
template: "<input type='button' onclick='deleteRow(\"${ProductID}\")' value='Delete' class='delete-button'/>"
My fixture data contains multiple array.Out of this multiple array cart_items contains some product data.
I am trying to calculate total no of products available in cart data (based on length of cart_items items) but i am not able to calculate no of items are present in cart_items.
In router i have selected application fixture as model for current route,as follow :
Astcart.IndexRoute = Ember.Route.extend({
model: function() {
return Astcart.Application.find();
}
});
Computed property code :
Astcart.IndexController = Ember.ArrayController.extend({
tot_cart_prd: function() {
return this.get("model.cart_items").get('length');
}.property("#each.isLoaded")
});
And my fixture data is :
Astcart.Application.adapter = Ember.FixtureAdapter.create();
Astcart.Application.FIXTURES = [
{
"logo_url": "img/logo.jpg",
"logged_in": {
"logged": true,
"username": "sachin",
"account_id": "4214"
},
"category_list": [
{
"id": "1",
"name": "Mobiles & Accessories"
},
{
"id": "2",
"name": "Computers & Software"
},
{
"id": "3",
"name": "Fashion"
},
{
"id": "4",
"name": "Electronics"
},
{
"id": "5",
"name": "Watches & Jewelry"
},
{
"id": "6",
"name": "Health & Beauty"
},
{
"id": "7",
"name": "Games"
},
{
"id": "8",
"name": "Books & Entertainment"
},
{
"id": "9",
"name": "Gaming"
},
{
"id": "10",
"name": "Shoes & Bags"
}
],
"cart_items": [
{
"id": "1",
"name": "Samsung Galaxy Tab 2",
"qty": "1",
"price": "1245.12",
"subtotal": "7842.23"
},
{
"id": "2",
"name": "Samsung Galaxy Tab 2",
"qty": "1",
"price": "1245.12",
"subtotal": "7842.23"
},
{
"id": "3",
"name": "Samsung Galaxy Tab 2",
"qty": "1",
"price": "1245.12",
"subtotal": "7842.23"
}
]
}
];
I have posted my code here(JSFiddle).
Can any one tell me why this.get("model.cart_items") is returning null?
Because your IndexController receive an array of Astcart.Application, from the route. You need to iterate in each application and get the length of each category list .
Your computed property need to be the following:
Astcart.IndexController = Ember.ArrayController.extend({
tot_cart_prd: function() {
var result = this.get('model').map(function(application) {
return application.get('category_list.length');
});
return result;
}.property('model.#each.category_list.length')
});
Here's an updated fiddle http://jsfiddle.net/marciojunior/PZZym/
I just looked at this and your core issue has something to do with the relationship setup between Application and Cart_items. The reason that this.get("model.cart_items").get('length') is failing is that this.get("model.cart_items") returns null. If you can get your relationship working you should be on the right track. I don't know anything about EmberModel, so I can't be of much help there.