Al C
Al C

Reputation: 5377

How to have a tap change only a single item in a ListView?

I'm using a ListView.builder() to display text items from a dynamic list. The text is displayed on Card() widgets. I'd like tapping the text to change its appearance to and from strikeout. I've tried declaring these variables, outside Build():

  bool isStrikeout = false;
  TextStyle _strikeout =
      TextStyle(fontSize: 16, decoration: TextDecoration.lineThrough);
  TextStyle _normal = TextStyle(fontSize: 16);

and then, within the Build() method:

  body: ListView.builder(
          itemCount: someList.length,
          itemBuilder: (ctx, index) {
            return Card(
              elevation: 8,
              child: ListTile(
                title: InkWell(
                  onTap: () {
                    setState(() {
                      isStrikeout = !isStrikeout;
                    });
                  },
                  child: Container(
                    padding: const EdgeInsets.all(8),
                    child: Text(
                      someList[index].text,
                      style: isStrikeout ? _strikeout : _normal,
                    ),
                  // more code here

The problem, of course, is that a user tapping any Card's text will toggle strikeout on and off for all Cards' texts. I only want it to happen for the tapped Card's text.

Upvotes: 1

Views: 777

Answers (2)

LihnNguyen
LihnNguyen

Reputation: 865

You try this way

 int _selectedIndex = 0;

  _onSelected(int index) {
    setState(() => _selectedIndex = index);
  }
InkWell(
   onTap:() => _onSelected(index),
) 
Text(
  someList[index].text,
  style: _selectedIndex == index ? _strikeout : _normal,
),

Upvotes: 1

MobIT
MobIT

Reputation: 980

You need to use List of bool.

  • Definition

    List<bool> strikeList = [];
    
  • Initialize

    strikeList = List.generate(someList.length, (index)=>false);
    
  • Usage

    body: ListView.builder(
            itemCount: someList.length,
            itemBuilder: (ctx, index) {
              return Card(
                elevation: 8,
                child: ListTile(
                  title: InkWell(
                    onTap: () {
                      setState(() {
                        bool temp = !strikeList[index];
                       strikeList.removeAt(index);
                       strikeList.insert(index, temp);
                      });
                    },
                    child: Container(
                      padding: const EdgeInsets.all(8),
                      child: Text(
                        someList[index].text,
                        style: strikeList[index] ? _strikeout : _normal,
                      ),
                    // more code here
    

Upvotes: 2

Related Questions