flutter 我可以添加其他小部件下面的列表磁贴

s4n0splo  于 2023-04-22  发布在  Flutter
关注(0)|答案(1)|浏览(116)

我在努力实现

屏幕,但我是新的,这不明白如何实现。我检查了许多代码,但没有帮助我,所以请帮助我。我是初学者在编码。
在这段代码中,我使用JSON文件,我能够显示列表瓷砖,但如图所示,我想添加一些文本和图标下面这个列表瓷砖,但当我添加任何小部件,它去一边领先
我不知道我该怎么做

import 'dart:convert';

    import          'package:flutter/material.dart';
import 'package:flutter/services.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: HomePage(),
    );
  }
}

class HomePage extends StatefulWidget {
  const HomePage({super.key});

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  List _items = [];

  // Fetch content from the json file
  Future<void> readJson() async {
    final String response = await rootBundle.loadString('assets/sample.json');
    final data = await json.decode(response);
    setState(() {
      _items = data["items"];
    });
  }

  @override
  void initState() {
    super.initState();
    // Call the readJson method when the app starts
    readJson();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        leading: IconButton(
          icon: const Icon(Icons.arrow_back, color: Colors.black),
          onPressed: () => Navigator.of(context).pop(),
        ),
        backgroundColor: Colors.white,
        centerTitle: true,
        elevation: 0,
        title: const Text(
          'Ask Help',
          style: TextStyle(color: Colors.black),
        ),
      ),
      body: Padding(
        padding: const EdgeInsets.fromLTRB(12, 0, 12, 0),
        child: Column(
          children: [
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: <Widget>[
                Column(
                  children: <Widget>[
                    ElevatedButton(
                      onPressed: () {},
                      style: ElevatedButton.styleFrom(
                        //change width and height on your need width = 200 and height = 50
                        minimumSize: Size(160, 50),
                      ),
                      child: const Text('Patient'),
                    )
                  ],
                ),
                Column(
                  children: <Widget>[
                    OutlinedButton(
                      style: OutlinedButton.styleFrom(
                          side: const BorderSide(color: Colors.blue, width: 1),
                          minimumSize: Size(160, 50)),
                      onPressed: () {},
                      child: const Text(
                        "NGO",
                        style: TextStyle(color: Colors.blue),
                      ),
                    ),
                  ],
                )
              ],
            ),
            // Display the data loaded from sample.json
            Container(
              child: _items.isNotEmpty
                  ? Expanded(
                      child: ListView.separated(
                        itemCount: _items.length,
                        separatorBuilder: (BuildContext context, int index) =>
                            Divider(height: 1),
                        itemBuilder: (context, index) {
                          return Padding(
                            padding: const EdgeInsets.all(8.0),
                            child: ListTile(
                              leading: CircleAvatar(
                                child:
                                    Text(_items[index]["imageUrl"].toString()),
                              ),
                              title: Text(_items[index]["name"]),
                              subtitle: Column(
                                  mainAxisAlignment: MainAxisAlignment.start,
                                  crossAxisAlignment: CrossAxisAlignment.start,
                                  children: <Widget>[
                                    Text(_items[index]["phone_number"],
                                        style: const TextStyle(
                                            fontSize: 13.0,
                                            fontWeight: FontWeight.normal)),
                                    Text(_items[index]["email_id"],
                                        style: const TextStyle(
                                            fontSize: 13.0,
                                            fontWeight: FontWeight.normal)),
                                    // Text(
                                    //   'Population: ${_items[index]["email_id"]}',
                                    //   style: const TextStyle(
                                    //       fontSize: 11.0,
                                    //       fontWeight: FontWeight.normal),
                                    // ),
                                    
                                  ]
                                  ),
                              trailing: const Icon(Icons.more_vert),
                              
                            ),
                            
                          );
                        },
                      ),
                    )
                  : Container(
                    //color: Colors.amber,
                  ),
            ),

            Align(
              alignment: Alignment.bottomCenter,
              child: Container(
                height: 70,
                child: Center(
                  child: ElevatedButton(
                    onPressed: () {},
                    style: ElevatedButton.styleFrom(
                      //change width and height on your need width = 200 and height = 50
                      minimumSize: Size(300, 50),
                    ),
                    child: const Text('Register'),
                  ),
                ),
              ),
            )
          ],
        ),
      ),
    );
  }
}

我的json代码:

{
    "items": [
        {
            "id": "p1",
            "name": "Item 1",
            "phone_number":"8975412369",
            "email_id":"abc@gmail.com",
            "description": "Description 1",
            "imageUrl": "https://m.media-amazon.com/images/I/81S-ekaE+vS._AC_UL320_.jpg"
        },
        {
            "id": "p2",
            "name": "Item 2",
            "phone_number": "8975412369",
            "email_id": "abc@gmail.com",
            "description": "Description 1",
            "imageUrl": "https://m.media-amazon.com/images/I/81S-ekaE+vS._AC_UL320_.jpg"
        },
        {
            "id": "p3",
            "name": "Item 3",
            "phone_number": "8975412369",
            "email_id": "abc@gmail.com",
            "description": "Description 1",
            "imageUrl": "https://m.media-amazon.com/images/I/81S-ekaE+vS._AC_UL320_.jpg"
        },
        {
            "id": "p1",
            "name": "Item 1",
            "phone_number": "8975412369",
            "email_id": "abc@gmail.com",
            "description": "Description 1",
            "imageUrl": "https://m.media-amazon.com/images/I/81S-ekaE+vS._AC_UL320_.jpg"
        },
        {
            "id": "p2",
            "name": "Item 2",
            "phone_number": "8975412369",
            "email_id": "abc@gmail.com",
            "description": "Description 1",
            "imageUrl": "https://m.media-amazon.com/images/I/81S-ekaE+vS._AC_UL320_.jpg"
        },
        {
            "id": "p3",
            "name": "Item 3",
            "phone_number": "8975412369",
            "email_id": "abc@gmail.com",
            "description": "Description 1",
            "imageUrl": "https://m.media-amazon.com/images/I/81S-ekaE+vS._AC_UL320_.jpg"
        },
        {
            "id": "p1",
            "name": "Item 1",
            "phone_number": "8975412369",
            "email_id": "abc@gmail.com",
            "description": "Description 1",
            "imageUrl": "https://m.media-amazon.com/images/I/81S-ekaE+vS._AC_UL320_.jpg"
        },
        {
            "id": "p2",
            "name": "Item 2",
            "phone_number": "8975412369",
            "email_id": "abc@gmail.com",
            "description": "Description 1",
            "imageUrl": "https://m.media-amazon.com/images/I/81S-ekaE+vS._AC_UL320_.jpg"
        },
        {
            "id": "p3",
            "name": "Item 3",
            "phone_number": "8975412369",
            "email_id": "abc@gmail.com",
            "description": "Description 1",
            "imageUrl": "https://m.media-amazon.com/images/I/81S-ekaE+vS._AC_UL320_.jpg"
        },{
            "id": "p1",
            "name": "Item 1",
            "phone_number": "8975412369",
            "email_id": "abc@gmail.com",
            "description": "Description 1",
            "imageUrl": "https://m.media-amazon.com/images/I/81S-ekaE+vS._AC_UL320_.jpg"
        },
        {
            "id": "p2",
            "name": "Item 2",
            "phone_number": "8975412369",
            "email_id": "abc@gmail.com",
            "description": "Description 1",
            "imageUrl": "https://m.media-amazon.com/images/I/81S-ekaE+vS._AC_UL320_.jpg"
        },
        {
            "id": "p3",
            "name": "Item 3",
            "phone_number": "8975412369",
            "email_id": "abc@gmail.com",
            "description": "Description 1",
            "imageUrl": "https://m.media-amazon.com/images/I/81S-ekaE+vS._AC_UL320_.jpg"
        }
    ]
}
z5btuh9x

z5btuh9x1#

这个问题的答案是肯定的!这里有一个最小的例子:

/* SAMPLE
        {
            "id": "p1",
            "name": "Item 1",
            "phone_number":"8975412369",
            "email_id":"abc@gmail.com",
            "description": "Description 1",
            "imageUrl": "https://m.media-amazon.com/images/I/81S-ekaE+vS._AC_UL320_.jpg"
        },
*/
class Item {
  Item({
    required this.id,
    required this.name,
    required this.phoneNumber,
    required this.emailId,
    required this.description,
    required this.imageUrl,
  });

  final String id;
  final String name;
  final String phoneNumber;
  final String emailId;
  final String description;
  final String imageUrl;

  factory Item.fromJson(Map<String, dynamic> json) => Item(
        id: json["id"],
        name: json["name"],
        phoneNumber: json["phone_number"],
        emailId: json["email_id"],
        description: json["description"],
        imageUrl: json["imageUrl"],
      );

  Map<String, dynamic> toJson() => {
        "id": id,
        "name": name,
        "phone_number": phoneNumber,
        "email_id": emailId,
        "description": description,
        "imageUrl": imageUrl,
      };

  static List<Item> fromJsonList(List<Map<String,dynamic>> jsonList) {
    final List<Item> items = [];
    for (var json in jsonList) {
      items.add(Item.fromJson(json));
    }
    return items;
  }
}

上面的类放在data_model.dart文件中。我已经为你做了一个数据模型。在处理UI之前,最好将代码组织成不同的部分。
还有一个自定义小部件,用于更轻松地处理东西和DRY规则!这将转到details.dart文件。

import 'package:flutter/material.dart';

import 'data_model.dart';

class DetailsPage extends StatelessWidget {
  const DetailsPage({super.key, required this.item});
  final Item item;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        leading: IconButton(
          icon: const Icon(Icons.arrow_back, color: Colors.black),
          onPressed: () => Navigator.of(context)
              .pop(), // No need to pop for now, there is nothing behind this screen :)
        ),
        backgroundColor: Colors.white,
        centerTitle: true,
        elevation: 0,
        title: const Text(
          'Ask Help',
          style: TextStyle(color: Colors.black),
        ),
      ),
      body: LayoutBuilder(builder: (context, constraints) {
        return SingleChildScrollView(
          child: ConstrainedBox(
            constraints: constraints,
            child: Column(
              children: [
                Padding(
                  padding: const EdgeInsets.symmetric(horizontal: 12),
                  child: Row(
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    children: <Widget>[
                      ElevatedButton(
                        onPressed: () {},
                        style: ElevatedButton.styleFrom(
                          backgroundColor: Colors.teal.withBlue(200),
                          //change width and height on your need width = 200 and height = 50
                          minimumSize: const Size(160, 50),
                        ),
                        child: const Text('Patient'),
                      ),
                      OutlinedButton(
                        style: OutlinedButton.styleFrom(
                            side:
                                const BorderSide(color: Colors.teal, width: 1),
                            minimumSize: const Size(160, 50)),
                        onPressed: () {},
                        child: const Text(
                          "NGO",
                          style: TextStyle(color: Colors.blue),
                        ),
                      ),
                    ],
                  ),
                ),
                const SizedBox(
                  height: 20,
                ),
                Padding(
                  padding: const EdgeInsets.symmetric(horizontal: 12),
                  child: DetailSection(item: item, viewAttachment: true),
                ),
                const SizedBox(
                  height: 10,
                ),
                const Divider(
                  color: Colors.black26,
                ),
                Padding(
                  padding: const EdgeInsets.symmetric(horizontal: 12),
                  child: DetailSection(
                      item: item,
                      viewAttachment: false,
                      skills: const ['plumber', '2 hrs']),
                ),
                const Divider(
                  color: Colors.black26,
                ),
                const Spacer(),
                Align(
                  alignment: Alignment.bottomCenter,
                  child: SizedBox(
                    height: 70,
                    child: Center(
                      child: ElevatedButton(
                        onPressed: () {},
                        style: ElevatedButton.styleFrom(
                          backgroundColor: Colors.teal.withBlue(200),
                          minimumSize: const Size(300, 50),
                        ),
                        child: const Text('Register'),
                      ),
                    ),
                  ),
                )
              ],
            ),
          ),
        );
      }),
    );
  }
}

class DetailSection extends StatelessWidget {
  final Item item;
  final List<String> skills;
  final bool viewAttachment;
  const DetailSection(
      {Key? key,
      required this.item,
      required this.viewAttachment,
      this.skills = const []})
      : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        ListTile(
          leading: CircleAvatar(
            radius: 35,
            backgroundColor: Colors.transparent,
            child: Image.network(item.imageUrl),
          ),
          title: Text(
            item.name,
            style: const TextStyle(fontWeight: FontWeight.bold),
          ),
          subtitle: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Text(item.phoneNumber,
                  style: const TextStyle(
                      fontSize: 13.0, fontWeight: FontWeight.normal)),
              Text(item.emailId,
                  style: const TextStyle(
                      fontSize: 13.0, fontWeight: FontWeight.normal)),
            ],
          ),
        ),
        const SizedBox(
          height: 10,
        ),
        if (skills.isNotEmpty) ...[
          const Align(
            alignment: Alignment.centerLeft,
            child: Text(
              'Skills',
              style: TextStyle(fontWeight: FontWeight.bold),
            ),
          ),
          const SizedBox(
            height: 15,
          ),
          Row(
            children: skills
                .map((e) => Container(
                    margin: const EdgeInsets.only(
                      right: 10,
                      bottom: 10,
                    ),
                    padding: const EdgeInsets.all(2),
                    decoration: BoxDecoration(
                        color: Colors.amberAccent.withOpacity(0.5),
                        borderRadius:
                            const BorderRadius.all(Radius.circular(12))),
                    child: Padding(
                      padding: const EdgeInsets.symmetric(horizontal: 6.0),
                      child: Text(e),
                    )))
                .toList(),
          )
        ],
        const Align(
          alignment: Alignment.centerLeft,
          child: Text(
            'Needs Help for',
            style: TextStyle(fontWeight: FontWeight.bold),
          ),
        ),
        const SizedBox(
          height: 10,
        ),
        const Align(
            alignment: Alignment.centerLeft,
            child: Text('Bluh bluh aaaaaaah I need help!')),
        const SizedBox(
          height: 10,
        ),
        if (viewAttachment)
          Row(
            children: const [
              Text(
                'View Attachment',
                style: TextStyle(fontWeight: FontWeight.bold),
              ),
              Spacer(),
              Icon(Icons.play_arrow_outlined),
            ],
          ),
      ],
    );
  }
}

编辑的main.dart:

import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'details.dart';

import 'data_model.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: HomePage(),
    );
  }
}

class HomePage extends StatefulWidget {
  const HomePage({super.key});

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  final List<Item> _items =
      []; // Don't use dynamic types. List<T> where T is your type is the better form :)

  // Fetch content from the json file
  Future<void> readJson() async {
    final String response = await rootBundle.loadString('assets/sample.json');
    // jsonDecode/json.decode are not futures. No need to "await" them.
    final rawItems = json.decode(response)['items'];
    final jsonList = rawItems.cast<Map<String, dynamic>>().toList();
    final items = Item.fromJsonList(jsonList);
    setState(() {
      _items.addAll(items);
    });
  }

  @override
  void initState() {
    super.initState();
    // Call the readJson method when the app starts
    readJson();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Colors.white,
        centerTitle: true,
        elevation: 0,
        title: const Text(
          'Item List',
          style: TextStyle(color: Colors.black),
        ),
      ),
      body: Padding(
        padding: const EdgeInsets.fromLTRB(12, 0, 12, 0),
        child: Container(
          child: _items.isNotEmpty
              ? ListView.separated(
                  itemCount: _items.length,
                  separatorBuilder: (BuildContext context, int index) =>
                      const Divider(height: 1),
                  itemBuilder: (context, index) {
                    final item = _items[
                        index]; // No need to use [index] for each item :)
                    return Padding(
                      padding: const EdgeInsets.all(8.0),
                      child: ListTile(
                        leading: CircleAvatar(
                          child: Image.network(item
                              .imageUrl), // Optionally, use cached_network_image package.
                        ),
                        title: Text(item.name),
                        subtitle: Column(
                            mainAxisAlignment: MainAxisAlignment.start,
                            crossAxisAlignment: CrossAxisAlignment.start,
                            children: <Widget>[
                              Text(item.phoneNumber,
                                  style: const TextStyle(
                                      fontSize: 13.0,
                                      fontWeight: FontWeight.normal)),
                              Text(item.emailId,
                                  style: const TextStyle(
                                      fontSize: 13.0,
                                      fontWeight: FontWeight.normal)),
                            ]),
                        trailing: const Icon(Icons.more_vert),
                        onTap: () =>
                            Navigator.of(context).push(MaterialPageRoute(
                                builder: ((context) => DetailsPage(
                                      item: item,
                                    )))),
                      ),
                    );
                  },
                )
              : const CircularProgressIndicator(),
        ),
      ),
    );
  }
}

我已经修改了UI代码来表示模型更改。
您的代码和JSON示例与您想要实现的链接图像有点远,但我使用了虚构的细节来向您表示更好的示例。请随意使用代码和UI。

相关问题