_pages.elementAt(_selectedIndex) 在 Flutter 中检查并授予存储权限后无法正确显示。

huangapple go评论65阅读模式
英文:

_pages.elementAt(_selectedIndex) doesn't show up properly after checking and granting storage permission in flutter

问题

我添加了一个条件块,当权限状态返回为拒绝时,会显示RequestPermissionPage小部件。它显示RequestPermissionPage小部件,并且按钮也按预期工作,但在授予权限后,主页面仍然不会正确显示。

我正在使用permission_handler与provider。
这是我的代码:

class _HomeState extends State<Home> {
  // ... 其他代码
}

class RequestPermissionPage extends StatelessWidget {
  // ... 其他代码
}

class AppPermissionState extends ChangeNotifier {
  // ... 其他代码
}

// ... 其他代码

Tried changing checkPermissionStatus() in AppPermissionState to the following code
Expected to show only the content in \_pages.elementAt(\_selectedIndex) right after granting permission and without restarting the app.
But shows RequestPermissionPage even after granting permission, strangely after restarting the app I can toggle elements in \_pages and RequestPermissionPage doesn't show after changing bottom navbar pages but RequestPermissionPage shows up every time app is opened. How do I fix it?
英文:

I added a condition block where RequestPermissionPage widget would show when permission status is returned as denied. It shows the RequestPermissionPage widget and the button to request permission also works as intended but after giving the permission, the main page still wont show properly.

I'm using permission_handler with provider.
Here is my code:

class _HomeState extends State<Home> {
  final AppPermissionState _perm = AppPermissionState();
  final List<Widget> _pages = [const HomePage(), RecentPage(), StoragePage()];
  @override
  void initState() {
    super.initState();
    _perm.checkPermissionStatus();
  }

  int _selectedIndex = 0;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: _perm.permissionStatus.isGranted
          ? _pages.elementAt(_selectedIndex) //this doesn't show after requesting
          : const RequestPermissionPage(), //this works as intended
      bottomNavigationBar: NavigationBar(
        destinations: const [
          NavigationDestination(
              icon: Icon(Icons.folder_open), label: "Library"),
          NavigationDestination(
              icon: Icon(Icons.timelapse_rounded), label: "Recent"),
          NavigationDestination(
              icon: Icon(Icons.storage_outlined), label: "Storage"),
        ],
        selectedIndex: _selectedIndex,
        labelBehavior: NavigationDestinationLabelBehavior.onlyShowSelected,
        onDestinationSelected: (value) {
          setState(() {
            _selectedIndex = value;
          });
        },
      ),
    );
  }
}
class RequestPermissionPage extends StatelessWidget {
  const RequestPermissionPage({super.key});

  @override
  Widget build(BuildContext context) {
    return Consumer<AppPermissionState>(
      builder: (context, permissionStateValue, child) {
        return Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            crossAxisAlignment: CrossAxisAlignment.center,
            children: [
              const Padding(
                padding: EdgeInsets.all(16.0),
                child: Text("This feature require storage permission"),
              ),
              FilledButton.tonal(
                onPressed: () {
                  permissionStateValue.requestPermission(); //this works as intended too
                },
                child: const Text("Grant Permission"),
              )
            ],
          ),
        );
      },
    );
  }
}

Permission provider:

class AppPermissionState extends ChangeNotifier {
  PermissionStatus _permissionStatus = PermissionStatus.denied;

  PermissionStatus get permissionStatus => _permissionStatus;

  Future<void> requestPermission() async {
    _permissionStatus = await Permission.manageExternalStorage.request();
    notifyListeners();
  }

  Future<void> checkPermissionStatus() async {
    _permissionStatus = await Permission.manageExternalStorage.status;
  }
}

Tested on Android Q, S and T

Permissions already mentioned in AndroidManifest.xml

<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" tools:ignore="ScopedStorage" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

Tried changing checkPermissionStatus() in AppPermissionState to the following code

Future<void> checkPermissionStatus() async {
    await requestPermission();
    _permissionStatus = await Permission.manageExternalStorage.status;
    notifyListeners();
  }

Expected to show only the content in _pages.elementAt(_selectedIndex) right after granting permission and without restarting the app.

But shows RequestPermissionPage even after granting permission, strangely after restarting the app I can toggle elements in _pages and RequestPermissionPage doesn't show after changing bottom navbar pages but RequestPermissionPage shows up every time app is opened. How do I fix it?

答案1

得分: 0

以下是您提供的代码的中文翻译:

上述问题已解决。不再在build()外部调用AppPermissionState,而是在build()内部调用它:

Widget build(BuildContext context) {
    final _perm = Provider.of<AppPermissionState>(context);
    _perm.checkPermissionStatus();
    if (_perm.permissionStatus.isGranted) {
      return _buildHomePage(); // 条件为true时返回成功
    } else {
      return const RequestPermissionPage(); // 条件为false时返回成功
    }
  }

RequestPermissionPage中,发现不需要使用Consumer构建器。而是在StatelessWidget类中用以下方式替换Cosumer构建器:

Widget build(BuildContext context) {
    final permissionStateValue = Provider.of<AppPermissionState>(context);
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            const Padding(
              padding: EdgeInsets.all(16.0),
              child: Text("此功能需要存储权限"),
            ),
            FilledButton.tonal(
              style: ButtonStyle(
                  alignment: Alignment.centerLeft,
                  padding: MaterialStateProperty.all(
                    const EdgeInsets.all(16.0),
                  ),
                  shape: MaterialStateProperty.all(
                    RoundedRectangleBorder(
                      borderRadius: BorderRadius.circular(16),
                    ),
                  )),
              onPressed: () {
                permissionStateValue.requestPermission();
              },
              child: const Text("请求权限"),
            )
          ],
        ),
      ),
    );
  }

权限提供程序保持不变:

class AppPermissionState extends ChangeNotifier {
  PermissionStatus _permissionStatus = PermissionStatus.denied;

  PermissionStatus get permissionStatus => _permissionStatus;

  Future<void> requestPermission() async {
    _permissionStatus = await Permission.manageExternalStorage.request();
    notifyListeners();
  }

  Future<void> checkPermissionStatus() async {
    _permissionStatus = await Permission.manageExternalStorage.status;
  }
}
英文:

The above problem is resolved. Instead of calling AppPermissionState outside build(), I had to call it inside build():

Widget build(BuildContext context) {
    final _perm = Provider.of&lt;AppPermissionState&gt;(context);
    _perm.checkPermissionStatus();
    if (_perm.permissionStatus.isGranted) {
      return _buildHomePage(); //returns successfully when condition is true
    } else {
      return const RequestPermissionPage(); //returns successfully when condition is false
    }
  }

and in RequestPermissionPage, turns out there isn't need for Consumer builder. Instead replaced Cosumer builder with this in a StatelessWidget class:

Widget build(BuildContext context) {
    final permissionStateValue = Provider.of&lt;AppPermissionState&gt;(context);
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            const Padding(
              padding: EdgeInsets.all(16.0),
              child: Text(&quot;This feature require storage permission&quot;),
            ),
            FilledButton.tonal(
              style: ButtonStyle(
                  alignment: Alignment.centerLeft,
                  padding: MaterialStateProperty.all(
                    const EdgeInsets.all(16.0),
                  ),
                  shape: MaterialStateProperty.all(
                    RoundedRectangleBorder(
                      borderRadius: BorderRadius.circular(16),
                    ),
                  )),
              onPressed: () {
                permissionStateValue.requestPermission();
              },
              child: const Text(&quot;Request Permission&quot;),
            )
          ],
        ),
      ),
    );
  }

The permission provider stays the same

class AppPermissionState extends ChangeNotifier {
  PermissionStatus _permissionStatus = PermissionStatus.denied;

  PermissionStatus get permissionStatus =&gt; _permissionStatus;

  Future&lt;void&gt; requestPermission() async {
    _permissionStatus = await Permission.manageExternalStorage.request();
    notifyListeners();
  }

  Future&lt;void&gt; checkPermissionStatus() async {
    _permissionStatus = await Permission.manageExternalStorage.status;
  }
}

huangapple
  • 本文由 发表于 2023年5月14日 20:25:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/76247475.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定