Flutter动态生成按钮的onPressed回调处理及点击变色需求
Hey there! Let's fix this step by step since you're new to Flutter—no worries, this is a common gotcha when dealing with dynamic buttons and state.
First, let's break down what's missing in your current code:
- You're using
currentHourto track the active button, but you're not updating it when a button is pressed (and triggering a UI rebuild to reflect the change). - There's also a potential closure trap in your for loop: if you run your current code, clicking any button might print the last value of
i(17) instead of the actual hour you clicked. That's because theivariable in theonPressedcallback references the same loop variable, which gets updated each iteration.
Here's the corrected approach:
Step 1: Make sure currentHour is a state variable
First, your widget needs to be a StatefulWidget (since we need to update the UI when state changes). In your State class, define:
int currentHour = 8; // Set your initial active hour here
Step 2: Rewrite the button list with proper state handling
Instead of a for loop adding to a list, use List.generate—this avoids the closure issue because each iteration gets its own independent hour variable. Then, update currentHour inside setState when a button is pressed:
List<Widget> workingHoursButtons() { // Generate 10 buttons (8 to 17 inclusive) return List.generate(10, (index) { final hour = 8 + index; return Padding( padding: const EdgeInsets.all(8.0), child: SizedBox( width: 59.0, height: 50.0, child: TextButton( // Note: FlatButton is deprecated, use TextButton instead style: TextButton.styleFrom( backgroundColor: hour == currentHour ? Color(0xff425660) : null, shape: RoundedRectangleBorder( side: BorderSide(), borderRadius: BorderRadius.circular(3.0), ), ), child: Text( "$hour", style: TextStyle( color: hour == currentHour ? Colors.white : null, fontSize: 16.0, fontWeight: FontWeight.bold, ), ), onPressed: hour < currentHour ? null : () { setState(() { currentHour = hour; }); }, ), ), ); }); }
Key changes explained:
List.generate: Creates each button with a uniquehourvariable, so theonPressedcallback always references the correct hour for that button.setState: Calling this tells Flutter that the state has changed, so it will rebuild the UI—this is what updates the button's background color when you click it.- Replaced
FlatButton:FlatButtonis no longer recommended;TextButtonwithstyleFromis the modern way to customize button appearance.
Bonus: If you need multi-select instead of single-select
If you want users to select multiple hours (e.g., a range), change currentHour to a Set<int>:
Set<int> selectedHours = {8}; // Initial selected hour
Then update the button logic:
// In the button style: backgroundColor: selectedHours.contains(hour) ? Color(0xff425660) : null, // In onPressed: onPressed: hour < currentHour // Or remove this if all buttons are selectable ? null : () { setState(() { if (selectedHours.contains(hour)) { selectedHours.remove(hour); } else { selectedHours.add(hour); } }); },
That should do it! Let me know if you run into any other issues as you learn Flutter.
内容的提问来源于stack exchange,提问作者Eyewritecode

