Shell页面跳转时,如何在目标页显示ActivityIndicator直至数据加载完成
问题分析
你的问题核心是UI线程被阻塞,导致Pending页面无法在数据加载过程中渲染ActivityIndicator,直到耗时操作完成后才一次性显示页面。具体原因有两点:
- Pending页的
GetMyObjects方法中,耗时操作直接在UI线程执行,阻塞了页面渲染流程; - 页面还未完成初始渲染就启动了同步耗时操作,ActivityIndicator根本没机会显示。
解决方案
1. 修正登录页LoginAsync逻辑
登录页的IsBusy仅控制自身加载状态,导航操作需异步执行,避免被Pending页的加载逻辑阻塞:
public async Task LoginAsync() { try { IsBusy = true; // 先完成登录验证(如果有) await PerformLoginChecks(); // 异步导航到Pending页,不等待页面加载完成 await Shell.Current.GoToAsync("//Pending"); } finally { IsBusy = false; } }
2. 将Pending页耗时操作移到后台线程
修改ViewModel的GetMyObjects方法,把耗时逻辑放到后台线程执行,同时确保IsBusy状态正确通知UI:
public class PendingViewModel : INotifyPropertyChanged { private bool _isBusy; public bool IsBusy { get => _isBusy; set { _isBusy = value; OnPropertyChanged(nameof(IsBusy)); } } public async Task GetMyObjects() { try { IsBusy = true; // 把耗时操作放到后台线程,避免阻塞UI await Task.Run(() => { // 模拟3秒耗时操作 Thread.Sleep(3000); // 实际业务:获取数据 // MyDataList = FetchFromApiOrDb(); }); } finally { IsBusy = false; } } public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged(string propName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName)); } }
3. 异步执行Pending页的加载逻辑
修改页面后台的OnAppearing方法,异步调用加载方法,让页面先完成渲染再启动数据加载:
protected override async void OnAppearing() { base.OnAppearing(); // 异步加载,确保页面先渲染出ActivityIndicator await LoadData(); } private async Task LoadData() { await ViewModel.GetMyObjects(); }
4. 验证XAML绑定正确性
确保ActivityIndicator的绑定逻辑正确,能响应IsBusy状态变化:
<ActivityIndicator IsRunning="{Binding IsBusy}" IsVisible="{Binding IsBusy}" HorizontalOptions="Center" VerticalOptions="Center"/>
关键原理
- UI线程仅负责页面渲染和用户交互,任何耗时操作必须放到后台线程,否则会导致UI冻结;
- Shell的
GoToAsync是异步操作,调用后会立即触发页面导航,但目标页面的同步耗时操作会阻塞渲染; IsBusy的更新必须触发PropertyChanged事件,否则UI无法感知状态变化。
内容的提问来源于stack exchange,提问作者Alex
相关产品推荐
相关产品推荐

