在Flutter中默认禁用BlocBuilder中的TextButton



我试图通过flutter Bloc库显示一个基本屏幕,其中一个人可以通过单击日历小部件中的特定日期查看他在特定日期的约会次数。

下面是上述屏幕的代码

import 'dart:developer';
import 'package:chikitsalaya/doctor/bloc/doctor_appointment_bloc.dart';
import 'package:chikitsalaya/doctor/bloc/doctor_appointment_event.dart';
import 'package:chikitsalaya/doctor/bloc/doctor_appointment_state.dart';
import 'package:chikitsalaya/doctor/doctor_appointment_details_screen.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:intl/intl.dart';
import '../common/common_ui.dart';
import '../payment/appointment_booking_payment.dart';
class DoctorAppointmentScreen extends StatelessWidget {
const DoctorAppointmentScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (BuildContext context) => DoctorAppointmentBloc(DoctorAppointmentInitial()),
child: Scaffold(
backgroundColor: Colors.white,
appBar: CommonUI(context).commonAppBar(),
drawer: CommonUI(context).commonDrawer(),
body: SafeArea(
minimum: const EdgeInsets.all(16.0),
child: Column(
children: <Widget>[
/// This is the Calendar Picker Widget , where doctor can pick a particular date and see what all appointments are present
buildCalendarWidget(context),
/// This is the BlocBuilder Widget for dynamically displaying all the appointments for a particular date picked above
BlocBuilder<DoctorAppointmentBloc,DoctorAppointmentState>(
builder: (context,state){
if(state is DoctorAppointmentDatePicked){
List<dynamic> currentDayAppointmentDetails = state.appointmentDetails;
return buildDailyAppointmentWidget(context,currentDayAppointmentDetails,state.day);
}else if(state is DoctorAppointmentInitial){
/// This is the initial state , so the date naturally would be the current date
context.read<DoctorAppointmentBloc>().add(DoctorAppointmentScreenOnDateChanged(DateTime.now()));
/// This is required because BlocBuilder requires a mandatory Widget to be returned back
return const CircularProgressIndicator();
}else if(state is DoctorAppointmentScreenError){
log("Error from Backend "+state.exceptionMessage);
return ErrorWidget(state.exceptionMessage);
}else if(state is DoctorAppointmentScreenNoAppointmentFound){
return Text("No Appointment Found for "+state.pickedDate);
}else if(state is DoctorAppointmentDetailsScreenInitial){
log("Inside state DoctorAppointmentDetailsScreenInitial");
//TODO: User View Resolver for this transition
Navigator.push(context, MaterialPageRoute(builder: (context) => DoctorAppointmentDetailsScreen(appointmentId:state.appointmentId)));
return const CircularProgressIndicator();
}else{
return const CircularProgressIndicator();
}
}
),
],
),
)
),
);
}
Widget buildCalendarWidget(BuildContext context) {
return BlocBuilder<DoctorAppointmentBloc,DoctorAppointmentState>(
builder: (context,state) {
return CalendarDatePicker(
initialDate: DateTime.now(),
firstDate: DateTime.now(),
lastDate: DateTime(2024),
onDateChanged: (dateTime) {
log('DateTime picked is '+dateTime.toString());
context.read<DoctorAppointmentBloc>().add(DoctorAppointmentScreenOnDateChanged(dateTime));
});
}
);
}
Card buildDailyAppointmentWidget(BuildContext context,List<dynamic> currentDayAppointmentDetails, String day){
return Card(
elevation: 6,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
child: Column(
children: <Widget>[
Text(day),
Expanded(
child: GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: (currentDayAppointmentDetails.length>=3) ? 3 : currentDayAppointmentDetails.length
),
itemCount: currentDayAppointmentDetails.length,
shrinkWrap: true,
itemBuilder: (context,index) {
return Padding(
padding: const EdgeInsets.only(left: 10.0,top: 40.0,right: 10.0,bottom: 40.0),
child: BlocBuilder<DoctorAppointmentBloc,DoctorAppointmentState>(
builder: (context,state) {
return TextButton(
/*style: ElevatedButton.styleFrom(
primary: Colors.green,
onPrimary: Colors.white,
shadowColor: Colors.greenAccent,
elevation: 3,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(32.0)),
),*/
onPressed: () {
try{
log("Pressed button");
print("Pressed someting");
context.read<DoctorAppointmentBloc>().add(DoctorAppointmentScreenOnPressed(currentDayAppointmentDetails[index]['appointmentId']));
}on Exception catch (_,error){
log("Error is "+error.toString());
}
},
//label: Text(currentDayAppointmentDetails![index]!['time']!),
//backgroundColor: Colors.green,
child: Text(currentDayAppointmentDetails![index]!['time']!),
);
}
),
);
}),
),
],
),
);
}
}

下面的代码运行良好,甚至在GridView中也正确地显示了appointmentList项。但是在按下任何单独的约会日期时,">onPressed";函数没有被调用。它甚至包括">print";日志和">";行。

onPressed: () {
try{
log("Pressed button");
print("Pressed someting");
context.read<DoctorAppointmentBloc>().add(DoctorAppointmentScreenOnPressed(currentDayAppointmentDetails[index]['appointmentId']));
}on Exception catch (_,error){
log("Error is "+error.toString());
}
},

我也试过使用">ElevatedButton &FloatingActionButton";而不是现有的">TextButton";但是似乎什么都不起作用。而且好像按钮在默认情况下被禁用了。

我真的被困在这里了,任何帮助都会很感激。

我还提供了Bloc, BlocState和BlocEvent代码

集团

import 'dart:async';
import 'dart:developer';
import 'package:chikitsalaya/appointment/appointment_service.dart';
import 'package:chikitsalaya/common/user_service.dart';
import 'package:chikitsalaya/doctor/bloc/doctor_appointment_event.dart';
import 'package:chikitsalaya/doctor/bloc/doctor_appointment_state.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:intl/intl.dart';
class DoctorAppointmentBloc extends Bloc<DoctorAppointmentEvent,DoctorAppointmentState>{
final AppointmentService _appointmentService = AppointmentServiceImpl();
final UserService _userService = UserServiceImpl();
DoctorAppointmentBloc(DoctorAppointmentState initialState) : super(initialState){
on<DoctorAppointmentScreenOnDateChanged>(_onDateChanged);
on<DoctorAppointmentDetailsScreenOnInit>(_onInitDetailsScreen);
on<DoctorAppointmentScreenOnPressed>(_onPressed);
}
/// OnDateChanged , need to fetch all the monthly appointments from backend
FutureOr<void> _onDateChanged(event,emit) async{
DateTime pickedDate = event.dateTime;
//TODO: Get the month of the pickedDate and pass it as a parameter for fetching data
String formattedDate = DateFormat('dd-MM-yyyy').format(pickedDate);
_appointmentService.fetchMonthlyAppointments("doctorId", "month")
.then((appointmentList) {
bool found = false;
for(int i=0;i<appointmentList.length;i++){
if(appointmentList[i].date==formattedDate){
found = true;
String weekDay = DateFormat('EEEE').format(pickedDate);
emit(DoctorAppointmentDatePicked(appointmentDetails: appointmentList[i].appointments,
day: weekDay));
}
if(!found){
log("No appointment found for date "+formattedDate);
emit(DoctorAppointmentScreenNoAppointmentFound(formattedDate));
}
}
}).onError((error, stackTrace) {
log("In DoctorAppointmentScreenBloc error "+error.toString());
log("In DoctorAppointmentScreenBloc stacktrace "+stackTrace.toString());
emit(DoctorAppointmentScreenError(error.toString()));
});
}

FutureOr<void> _onInitDetailsScreen(event, emit) async{
String appointmentId = (event as DoctorAppointmentDetailsScreenOnInit).appointmentId;
_appointmentService.fetchAppointmentDetails(appointmentId)
.then((appointment) {
log("Appointment Found for Id "+appointmentId+" "+appointment.toString());
/// After fetching appointment details , need to fetch Patient details via Patient API
String patientId = appointment.patientId;
_userService.fetchPatientDetails(patientId)
.then((patient) {
log("Patient details found for Id "+patientId+" "+patient.toString());
appointment.patientName=patient.patientName;
appointment.patientAge=patient.patientAge;
appointment.patientSex=patient.patientSex;
emit(DoctorAppointmentDetailsScreenSuccess(appointment));
}).onError((error, stackTrace) {
log("Failed to fetch Patient details for Id "+patientId+" "+stackTrace.toString());
emit(DoctorAppointmentDetailsScreenError(error.toString()));
});
}).onError((error, stackTrace) {
log("Failed to fetch Appointment details for Id "+appointmentId+" "+stackTrace.toString());
emit(DoctorAppointmentDetailsScreenError(error.toString()));
});
}
FutureOr<void> _onPressed(event, emit) async{
String appointmentId = (event as DoctorAppointmentScreenOnPressed).appointmentId;
log("Inside AppointmentBloc OnPressed "+appointmentId);
emit(DoctorAppointmentDetailsScreenInitial(appointmentId));
}
}

BlocEvent

import 'package:equatable/equatable.dart';
abstract class DoctorAppointmentEvent extends Equatable {
const DoctorAppointmentEvent();
}
class DoctorAppointmentStarted extends DoctorAppointmentEvent {
@override
List<Object?> get props => [];
}
class DoctorAppointmentScreenOnDateChanged extends DoctorAppointmentEvent {
final DateTime dateTime;
//TODO: Add Doctor ID as variable here
const DoctorAppointmentScreenOnDateChanged(this.dateTime);
@override
List<Object?> get props => [dateTime];
}
class DoctorAppointmentScreenOnPressed extends DoctorAppointmentEvent {
final String appointmentId;
const DoctorAppointmentScreenOnPressed(this.appointmentId);
@override
List<Object?> get props => [appointmentId];
}
class DoctorAppointmentDetailsScreenOnInit extends DoctorAppointmentEvent {
final String appointmentId;
const DoctorAppointmentDetailsScreenOnInit(this.appointmentId);
@override
List<Object?> get props => [];
}

BlocState

import 'package:chikitsalaya/appointment/appointment_model.dart';
import 'package:equatable/equatable.dart';
abstract class DoctorAppointmentState extends Equatable {
const DoctorAppointmentState();
}
class DoctorAppointmentInitial extends DoctorAppointmentState {
const DoctorAppointmentInitial();
@override
List<Object?> get props => [];
}
class DoctorAppointmentDatePicked extends DoctorAppointmentState {
final List<dynamic> appointmentDetails;
final String day;
const DoctorAppointmentDatePicked({required this.appointmentDetails,required this.day});
@override
List<Object?> get props => [appointmentDetails,day];
}
class DoctorAppointmentScreenError extends DoctorAppointmentState {
final String exceptionMessage;
const DoctorAppointmentScreenError(this.exceptionMessage);
@override
List<Object?> get props => [exceptionMessage];
}
class DoctorAppointmentScreenNoAppointmentFound extends DoctorAppointmentState {
final String pickedDate;
const DoctorAppointmentScreenNoAppointmentFound(this.pickedDate);
@override
List<Object?> get props => [pickedDate];
}
class DoctorAppointmentDetailsScreenInitial extends DoctorAppointmentState {
final String appointmentId;
const DoctorAppointmentDetailsScreenInitial(this.appointmentId);
@override
List<Object?> get props => [appointmentId];
}
class DoctorAppointmentDetailsScreenSuccess extends DoctorAppointmentState {
final Appointment appointment;
const DoctorAppointmentDetailsScreenSuccess(this.appointment);
@override
List<Object?> get props => [appointment];
}
class DoctorAppointmentDetailsScreenError extends DoctorAppointmentState {
final String exceptionMessage;
const DoctorAppointmentDetailsScreenError(this.exceptionMessage);
@override
List<Object?> get props => [exceptionMessage];
}

问题与GridView有关。如果GridView的itemBuilder返回一个带有子控件的InkWell,你就可以在InkWell上添加一个onTap事件来调用

context.read<DoctorAppointmentBloc>().add(DoctorAppointmentScreenOnPressed(currentDayAppointmentDetails[index]['appointmentId']));`

似乎你不允许在父卡内添加可点击的卡片。
所以,当我改变我的父小部件返回而不是卡片,它工作。

总之
旧代码

return Card(
elevation: 6,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
child: Column(

return Column(
children: <Widget>[
Text(day),
Expanded(

最新更新