Search code examples
flutterflutter-layout

Is there any way to topRight align ExpansionTile trailing icon


How to make the expansionTile trailing icon top align. by default it aligns to the center, below I have attached the screenshot of the desired output.

enter image description here

  ClipRRect(
          borderRadius: BorderRadius.circular(4),
          child: ExpansionTile(
            tilePadding: EdgeInsets.all(15),
            collapsedBackgroundColor: Color.fromRGBO(24, 34, 62, 1),
            backgroundColor: Color.fromRGBO(24, 34, 62, 1),
            iconColor: Colors.white,
            collapsedIconColor: Colors.white,
            expandedCrossAxisAlignment: CrossAxisAlignment.start,
            title: Column(
              children: [
                Row(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(
                      "text".toUpperCase(),
                      style: TextStyle(
                        color: Color.fromARGB(255, 14, 248, 26),
                      ),
                    ),
                    const SizedBox(width: 12),
                    Expanded(
                      child: Row(
                        mainAxisAlignment: MainAxisAlignment.spaceBetween,
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: [
                          Column(
                            crossAxisAlignment: CrossAxisAlignment.start,
                            children: [
                              Text(
                                'How to make trailing icon top align   ',
                                style: TextStyle(
                                    fontWeight: FontWeight.w600,
                                    color: Color.fromRGBO(0, 249, 85, 1),
                                    fontSize: 12),
                              ),
                              Container(
                                margin: const EdgeInsets.only(top: 3),
                                constraints: const BoxConstraints(minWidth: 80),
                                decoration: BoxDecoration(
                                    color: Color.fromRGBO(226, 80, 95, 1),
                                    borderRadius: BorderRadius.circular(2)),
                                padding:
                                    const EdgeInsets.symmetric(vertical: 2),
                                child: Text(
                                  'label',
                                  textAlign: TextAlign.center,
                                  style: TextStyle(
                                      color: Colors.black,
                                      fontSize: 10,
                                      fontWeight: FontWeight.w600),
                                ),
                              )
                            ],
                          ),
                          Text(
                            '40%',
                            style: TextStyle(
                                fontSize: 20,
                                color: Color.fromARGB(255, 14, 248, 26),
                                fontWeight: FontWeight.w700),
                          )
                        ],
                      ),
                    )
                  ],
                )
              ],
            ),
            children: const <Widget>[
              ListTile(title: Text('This is tile number 1')),
            ],
          ),
        ),`

here's the link to my Codepen


Solution

  • You can create custom widget for this, I am using Transformoffset to handle it.

    class MyApp extends StatefulWidget {
      const MyApp({Key? key}) : super(key: key);
    
      @override
      State<MyApp> createState() => _MyAppState();
    }
    
    class _MyAppState extends State<MyApp> {
      ValueNotifier<bool> isExpanded = ValueNotifier(false);
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: Column(
            children: [
              ClipRRect(
                borderRadius: BorderRadius.circular(4),
                child: ExpansionTile(
                  tilePadding: EdgeInsets.all(15),
                  collapsedBackgroundColor: Color.fromRGBO(24, 34, 62, 1),
                  backgroundColor: Color.fromRGBO(24, 34, 62, 1),
                  iconColor: Colors.white,
                  collapsedIconColor: Colors.white,
                  expandedCrossAxisAlignment: CrossAxisAlignment.start,
                  trailing: Transform.translate(
                    offset: Offset(0, -7), //half of padding
                    child: ValueListenableBuilder<bool>(
                      valueListenable: isExpanded,
                      builder: (context, value, child) => AnimatedSwitcher(
                        duration: Duration(milliseconds: 100),
                        child: Icon(value
                            ? Icons.keyboard_arrow_down_outlined
                            : Icons.keyboard_arrow_up),
                      ),
                    ),
                  ),
                  onExpansionChanged: (value) {
                    isExpanded.value = value;
                  },
                  title: Column(
                    children: [
                      Row(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: [
                          Text(
                            "text".toUpperCase(),
                            style: TextStyle(
                              color: Color.fromARGB(255, 14, 248, 26),
                            ),
                          ),
                          const SizedBox(width: 12),
                          Expanded(
                            child: Row(
                              mainAxisAlignment: MainAxisAlignment.spaceBetween,
                              crossAxisAlignment: CrossAxisAlignment.start,
                              children: [
                                Column(
                                  crossAxisAlignment: CrossAxisAlignment.start,
                                  children: [
                                    Text(
                                      'How to make trailing icon top align   ',
                                      style: TextStyle(
                                          fontWeight: FontWeight.w600,
                                          color: Color.fromRGBO(0, 249, 85, 1),
                                          fontSize: 12),
                                    ),
                                    Container(
                                      margin: const EdgeInsets.only(top: 3),
                                      constraints:
                                          const BoxConstraints(minWidth: 80),
                                      decoration: BoxDecoration(
                                          color: Color.fromRGBO(226, 80, 95, 1),
                                          borderRadius: BorderRadius.circular(2)),
                                      padding:
                                          const EdgeInsets.symmetric(vertical: 2),
                                      child: Text(
                                        'label',
                                        textAlign: TextAlign.center,
                                        style: TextStyle(
                                            color: Colors.black,
                                            fontSize: 10,
                                            fontWeight: FontWeight.w600),
                                      ),
                                    )
                                  ],
                                ),
                                Text(
                                  '40%',
                                  style: TextStyle(
                                      fontSize: 20,
                                      color: Color.fromARGB(255, 14, 248, 26),
                                      fontWeight: FontWeight.w700),
                                )
                              ],
                            ),
                          )
                        ],
                      )
                    ],
                  ),
                  children: const <Widget>[
                    ListTile(title: Text('This is tile number 1')),
                  ],
                ),
              ),
            ],
          ),
        );
      }
    }
    
    

    enter image description here