Want to show border if selected – flutter

Issue

I wanted to implement theming in my flutter app – I got to the point where I can successfully change themes and the dialog to change them pops up as expected… now I want to show the user which theme is selected so I wanted to have a border that goes around the selected theme as in the screenshot

themepicker

Thats the code I used so far for picking the theme and for displaying the themepickercontainers

    class MultiThemeModel {
      int index;
      String themeName;
      Color color;
      bool selected;
    
      MultiThemeModel(
          {required this.index,
          required this.themeName,
          required this.color,
          required this.selected});
    }
    
    titlesForThemeModel(int index) {
      switch (index) {
        case 0:
          return 'Luxury Purple';
        case 1:
          return 'Red Wine';
      }
      return 'No theme for index';
    }
    
    colorsForThemeModel(int index) {
      switch (index) {
        case 0:
          return purpleBackgroundColor;
        case 1:
          return redBackgroundColor;
      }
    }
    
    selectedForThemeModel(int index) {
      switch (index) {
        case 0:
          return true;
        case 1:
          return false;
      }
    }
    
    List<MultiThemeModel> get themes => List<MultiThemeModel>.generate(
        2,
        (index) => MultiThemeModel(
            index: index,
            themeName: titlesForThemeModel(index),
            color: colorsForThemeModel(index),
            selected: selectedForThemeModel(index)));
    
    List<Widget> get widgets => themes
        .map((themeData) => MultipleThemeViewerWidget(themeData: themeData))
        .toList();
    
    class MultipleThemeViewerWidget extends StatefulWidget {
  MultipleThemeViewerWidget({Key? key, required this.themeData})
      : super(key: key);
  final MultiThemeModel themeData;

  @override
  State<MultipleThemeViewerWidget> createState() =>
      _MultipleThemeViewerWidgetState();
}

class _MultipleThemeViewerWidgetState extends State<MultipleThemeViewerWidget> {
  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () {
        getThemeManager(context).selectThemeAtIndex(widget.themeData.index);
        setState(() {
          // selectedForThemeModel(widget.themeData.index) =
          widget.themeData.selected = !widget.themeData.selected;
        });
      },
      child: Container(
        height: 60,
        width: 105,
        decoration: BoxDecoration(
            borderRadius: BorderRadius.circular(10),
            color: widget.themeData.color.withOpacity(.3),
            border: widget.themeData.selected
                ? Border.all(color: widget.themeData.color, width: 3)
                : Border.all(color: Colors.white)),
        child: Center(
          child: Text(
            widget.themeData.themeName,
            style: GoogleFonts.poppins(
              textStyle: TextStyle(
                fontSize: 12,
                fontWeight: FontWeight.bold,
                color: widget.themeData.color,
              ),
            ),
          ),
        ),
      ),
    );
  }
}

now as far as I can imagine that it should work if id be able to change the return statement of selectedForThemeModel in the onTap function of the MultipleThemeViewerWidget… my problem is that I don’t know whether that is even possible and if so how it would be implemented in the onTap function

thanks for your help in advance!

Solution

I think what you need is a little rebuilding, try converting to stateful widget and try the below

 return GestureDetector(
      onTap: () {
        getThemeManager(context).selectThemeAtIndex(themeData.index);

        setState(() {});
      },

EDIT
A little refreshing was exactly what we needed but setState wasn’t the answer.

With the use of ValueNotifier, we can update the state immediately we change it.

Here are the changes

class MultiThemeModel {
  int index;
  String themeName;
  Color color;
  ValueNotifier<bool> selected;

  MultiThemeModel(
      {required this.index,
      required this.themeName,
      required this.color,
      required this.selected});
}

selectedForThemeModel(int index) {
  switch (index) {
    case 0:
      return ValueNotifier(true);
    case 1:
      return ValueNotifier(false);
  }
}

class MultipleThemeViewerWidget extends StatefulWidget {
  MultipleThemeViewerWidget(
      {Key? key, required this.themeData, required this.themes})
      : super(key: key);
  MultiThemeModel themeData;
  List<MultiThemeModel> themes;
  @override
  State<MultipleThemeViewerWidget> createState() =>
      _MultipleThemeViewerWidgetState();
}

class _MultipleThemeViewerWidgetState extends State<MultipleThemeViewerWidget> {
  @override
  Widget build(BuildContext context) {
    return ValueListenableBuilder(
        valueListenable: widget.themeData.selected,
        builder: (context, bool selected, _) {
          return GestureDetector(
            onTap: () {
              getThemeManager(context)
                  .selectThemeAtIndex(widget.themeData.index);
              if (!selected) {
                widget.themeData.selected.value = true;
                widget.themes
                    .elementAt(widget.themeData.index == 0 ? 1 : 0)
                    .selected
                    .value = false;
              }
            },
            child: Container(
              height: 60,
              width: 105,
              decoration: BoxDecoration(
                  borderRadius: BorderRadius.circular(10),
                  color: widget.themeData.color.withOpacity(.3),
                  border: selected
                      ? Border.all(color: widget.themeData.color, width: 3)
                      : Border.all(color: Colors.white)),
              child: Center(
                child: Text(
                  widget.themeData.themeName,
                  style: TextStyle(
                    fontSize: 12,
                    fontWeight: FontWeight.bold,
                    color: widget.themeData.color,
                  ),
                ),
              ),
            ),
          );
        });
  }

  @override
  void dispose() {
    widget.themeData.selected.dispose();
    super.dispose();
  }
}

Answered By – Frank nike

Answer Checked By – Jay B. (FlutterFixes Admin)

Leave a Reply

Your email address will not be published. Required fields are marked *