Flutter软件盘遮挡文本框问题

SingleChildScrollView

通过 SingleChildScrollView 来触发视图滚动
防止 页面超出可见范围 发出警告信息问题!

1
2
3
4
5
body: SingleChildScrollView(
// 滚动效果 弹性滚动
physics: BouncingScrollPhysics(),
child: ...
)

属性介绍

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Key key,
//滚动方向,默认是垂直方向
this.scrollDirection = Axis.vertical,
//是否按照阅读方向相反的方向滑动
this.reverse = false,
//内容边距
this.padding,
//是否使用widget树中默认的PrimaryScrollController
bool primary,
//此属性接受一个ScrollPhysics类型的对象,它决定可以滚动如何响应用户操作,比如用户滑动完抬起手指后,继续执行动画,或者滑动到边界时,如何显示。
//默认情况下,Flutter会根据具体平台分别使用不同的ScrollPhysics对象,对应不同的显示效果,如当滑动到边界时,继续拖动的话,在iOS上会出现弹性效果,
//而在Android上会出现微光效果。如果你想在所有平台下使用同一种效果,可以显示指定一个固定的ScrollPhysics。
//Flutter SDK包含两个ScrollPhysics的子类。1.ClampingScrollPhysics:Android下微光效果,2.BouncingScrollPhysics:iOS下弹性效果
this.physics,
//此属性接收一个ScrollController对象,ScrollController的主要作用是控制滚动位置和监听滚动事件。
//默认情况下,Widget树中会有一个默认的PrimaryScrollController,如果子树中的可滚动组件没有显示的指定controller,并且primary属性值为true时,可滚动组件会使用这个默认的ScrollController。
//这种机制带来的好处是父组件可以控制子树中可滚动的滚动行为,例:scaffold正是使用这种机制在iOS中实现了点击导航回到顶部的功能。
this.controller,
this.child,

resizeToAvoidBottomInset

用来防止软键盘弹出时遮挡页面的东西。值默认为 true
当设置为 true 的时候,软键盘弹出页面会自动调整尺寸避免遮挡
当为 false 的时候则软键盘弹出不会自动调整尺寸

1
2
3
Scaffold(
resizeToAvoidBottomInset: true
)

Column 无限高度溢出警告

Column 是一个 假的无限高的(屏幕高度) 布局容器, 当其 children 内容超出屏幕高度时,就会出现BottomOverflowdAlert警告问题!

ListView

ListView小部件也是一个无限高度的小部件,当应用在Column中,就会出现报错问题,

Expanded

Expanded 扩展小部件,将包含的child的小部件的内容,扩充占满整个剩余空间位置!
Expanded小部件extends flex,使内容区域改变为弹性布局!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(title, style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold),),

// Text('${this.isShowMoreBtn ? '更多' : ''}', style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold))
TextButton(onPressed: moreBtnOnTab, child: Text(isShowMoreBtn ? '更多' : '', style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold)))

],
),

Expanded( flex: 1, child: child)
],
),

container 外层包裹 inkwell 没有水波纹问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import 'package:flutter/material.dart';

class IndexNavgaitorBox extends StatefulWidget {

final String labelName;

final Color color;

final VoidCallback onTap;

const IndexNavgaitorBox({super.key, required this.labelName, required this.color, required this.onTap});

@override
State<IndexNavgaitorBox> createState() => _IndexNavgaitorBoxState();
}

class _IndexNavgaitorBoxState extends State<IndexNavgaitorBox> {

@override
Widget build(BuildContext context) {
return Column(
children: [
// Material -> Ink 解决 InkWell 包裹 Container 水波纹失效问题!
// Material 这个不能少
Material(
color: widget.color,
borderRadius: BorderRadius.circular(20),
child: Ink(
width: 50,
height: 50,
/* decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: e["color"],
), */
child: InkWell(
// 飞溅色
splashColor: Colors.cyanAccent[66],
// 高亮颜色
highlightColor: widget.color,
borderRadius: BorderRadius.circular(20),
onTap: widget.onTap,
),
),
),
Padding(
padding: const EdgeInsets.only(top: 6),
child: Text('${widget.labelName}', style: const TextStyle(fontSize: 14, fontWeight: FontWeight.bold),),
)
],
);
}
}

引入外部dart文件引起的问题

问题描述

当页面引入一个外部已封装好的widget小部件时,通过GlobalKey试图去访问widget小部件内部state状态时,显示报错无法引入!

上面附件是在main.dart中引入了Counter.dart小部件,并使用GlobalKey试图去获取state状态,但是无法获取到state!
造成此问题原因是_CounterState此中带了_下划线标识。

dart中的_下划线(私有)

Dart 中定义变量时,下划线的作用?定义变量或者方法前使用下划线,这样保证只有在定义该变量或者方法的.dart文件中可见
_属性 _方法 _类 都只会在定义.dart文件中可见!

Counter.dart

Counter.dart
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import 'package:flutter/material.dart';

class Counter extends StatefulWidget {
final int count;

const Counter({super.key, this.count = 0});

@override
//State<Counter> createState() => _CounterState();
State<Counter> createState() => CounterState();
}

class CounterState extends State<Counter> {
int counter = 0;

@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
setState(() {
counter++;
});
},
child: Container(
width: 150,
height: 150,
margin: const EdgeInsets.only(bottom: 5),
alignment: Alignment.center,
decoration: BoxDecoration(
color: Colors.grey.shade500,
borderRadius: BorderRadius.circular(12)),
child: Text(
'$counter',
style: const TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
),
),
);
}
}

main.dart

main.dart
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
import 'package:flutter/material.dart';
import 'package:flutter_mac_app/Counter.dart';

void main() {
runApp(const MyApp());
}

class MyApp extends StatelessWidget {
const MyApp({super.key});

// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Mac App',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.blueGrey),
useMaterial3: true,
),
home: const MyHomePage(title: 'Flutter Mac App'),
);
}
}

class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});

final String title;

@override
State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
// _CounterState 这个地方引用后访问不到 Counter.dart 中所定义的 _CounterState
//final _globalKey = GlobalKey<_CounterState>();
final _globalKey = GlobalKey<CounterState>();
void _incrementCounter() {
print(_globalKey.currentState?.counter);
setState(() {
_counter++;
});
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
),
body: Center(
child: Flex(
mainAxisAlignment: MainAxisAlignment.center,
direction: Axis.vertical,
children: [
Counter(key: _globalKey, count: _counter),
Center(child: Counter(count: _counter))
]),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
}
}

引用中, 去除”下划线“就行!

stack 定位溢出问题

前言

在做项目练习的时候碰到一个这样的问题:
就是我在一个模块做了一个图片附件相关功能,选择本地图片后并以缩略图的形式展示在面板中,这时我想通过拖拽缩略图的形式到目标处可以进行删除,于是乎
我就使用了stack定位小部件 并结合 dragable dragTarget 小部件来实现此功能!

问题

我试图将dragTarget 拖拽目标小部件通过AnimatedPositioned定位至设备边缘,无论是底部,还是 左侧 和 右侧,我都需要设置 top``left``right bottom 值来动态控制小部件的位置, 因此我设置了clipBehavior.none 属性防止 超出部分的内容被裁减导致超出的内容无法被看到的问题!
虽然我将dragTarget 小部件设置到了预想的位置, 但是让我没想道的问题发生了,由 dragable 拖拽 至 dragTarget -> 目标小部件所提供的回调函数并未执行这让我郁闷了半天, 后来发现, 把 top``left``right bottom 这几项 不为0 的设置为 0 然后就可以了~
后来寻资料,才知道 stack 定位小部件,内容定位超出的部分,交互事件会被忽视掉,额。。。。郁闷,定位不就是为了让内容,可以随处叠放吗,为什么把小部件超出的部分交互给取消掉了呢~

方案

如果想让它响应手势,我们可以用 Column 来组合一个完全相同的组件:

从下往上排列;
将上方的组件向下平移。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Column(
verticalDirection: VerticalDirection.up,
children: [
Container(
width: 200,
height: 100,
color: Colors.red,
),
Transform.translate(
offset: const Offset(0, 30),
child: GestureDetector(
onTap: () {
print('点击橙色view');
},
child: Container(
width: 60,
height: 60,
color: Colors.orange,
),
),
),
],
),

flutter打包apk报错

报错信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
➜  flutter_rent_house_demo git:(dev-rent_house) ✗ flutter build apk

Checking the license for package Android SDK Platform 31 in /Users/miaojiangwei/Library/Android/sdk/licenses
License for package Android SDK Platform 31 accepted.
Preparing "Install Android SDK Platform 31 (revision: 1)".
"Install Android SDK Platform 31 (revision: 1)" ready.
Installing Android SDK Platform 31 in /Users/miaojiangwei/Library/Android/sdk/platforms/android-31
"Install Android SDK Platform 31 (revision: 1)" complete.
"Install Android SDK Platform 31 (revision: 1)" finished.
Font asset "MaterialIcons-Regular.otf" was tree-shaken, reducing it from 1645184 to 5260 bytes (99.7% reduction). Tree-shaking can be disabled by providing the --no-tree-shake-icons flag when building your app.

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':app:bundleReleaseResources'.
> A failure occurred while executing com.android.build.gradle.internal.res.Aapt2ProcessResourcesRunnable
> Android resource linking failed
/Users/miaojiangwei/工作/workspace/flutter/flutter_rent_house_demo/build/app/intermediates/bundle_manifest/release/AndroidManifest.xml:52: error: unexpected element <uses-permission> found in <manifest><application>.
/Users/miaojiangwei/工作/workspace/flutter/flutter_rent_house_demo/build/app/intermediates/bundle_manifest/release/AndroidManifest.xml:54: error: unexpected element <uses-permission> found in <manifest><application>.
/Users/miaojiangwei/工作/workspace/flutter/flutter_rent_house_demo/build/app/intermediates/bundle_manifest/release/AndroidManifest.xml:56: error: unexpected element <uses-permission> found in <manifest><application>.


* Try:
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.

* Get more help at https://help.gradle.org

BUILD FAILED in 1m 42s
Running Gradle task 'assembleRelease'... 102.7s
Gradle task assembleRelease failed with exit code 1

问题处理

/build/app/intermediates/bundle_manifest/release/AndroidManifest.xml

根据错误提示: AndroidManifest.xml error: unexpected element <uses-permission> found in <manifest><application>
格式输入嵌套有问题!

正确格式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<manifest>
<uses-permission />
<permission />
<permission-tree />
<permission-group />
<instrumentation />
<uses-sdk />
<uses-configuration />
<uses-feature />
<supports-screens />
<compatible-screens />
<supports-gl-texture />

<application>

<activity>
<intent-filter>
<action />
<category />
<data />
</intent-filter>
<meta-data />
</activity>

<activity-alias>
<intent-filter> . . . </intent-filter>
<meta-data />
</activity-alias>

<service>
<intent-filter> . . . </intent-filter>
<meta-data/>
</service>

<receiver>
<intent-filter> . . . </intent-filter>
<meta-data />
</receiver>

<provider>
<grant-uri-permission />
<meta-data />
<path-permission />
</provider>

<uses-library />

</application>

</manifest>

修改调整 xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.rent_house">
<!-- 写入文件权限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- 读取文件权限 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<!-- 相机权限 -->
<uses-permission android:name="android.permission.CAMERA" />
<application
android:label="rent_house"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop"
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. -->
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme"
/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<!-- uses-permission 应该与 application 标签同级 -->
<!-- 写入文件权限 -->
<!-- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> -->
<!-- 读取文件权限 -->
<!-- <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> -->
<!-- 相机权限 -->
<!-- <uses-permission android:name="android.permission.CAMERA" /> -->
<meta-data
android:name="flutterEmbedding"
android:value="2" />
</application>
</manifest>

Build Error:uses-sdk:minSdkVersion 16

Error: uses-sdk:minSdkVersion 16 cannot be smaller than version 19 declared in library [:device_info_plus]

报错信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
Font asset "MaterialIcons-Regular.otf" was tree-shaken, reducing it from 1645184 to 5844 bytes (99.6% reduction). Tree-shaking can be disabled by providing the --no-tree-shake-icons flag when building your app.
/Users/miaojiangwei/工作/workspace/flutter/flutter_rent_house_demo/android/app/src/main/AndroidManifest.xml Error:
uses-sdk:minSdkVersion 16 cannot be smaller than version 19 declared in library [:device_info_plus] /Users/miaojiangwei/工作/workspace/flutter/flutter_rent_house_demo/build/device_info_plus/intermediates/merged_manifest/release/AndroidManifest.xml as the library might be using APIs not available in 16
Suggestion: use a compatible library with a minSdk of at most 16,
or increase this project's minSdk version to at least 19,
or use tools:overrideLibrary="dev.fluttercommunity.plus.device_info" to force usage (may lead to runtime failures)

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':app:processReleaseMainManifest'.
> Manifest merger failed : uses-sdk:minSdkVersion 16 cannot be smaller than version 19 declared in library [:device_info_plus] /Users/miaojiangwei/工作/workspace/flutter/flutter_rent_house_demo/build/device_info_plus/intermediates/merged_manifest/release/AndroidManifest.xml as the library might be using APIs not available in 16
Suggestion: use a compatible library with a minSdk of at most 16,
or increase this project's minSdk version to at least 19,
or use tools:overrideLibrary="dev.fluttercommunity.plus.device_info" to force usage (may lead to runtime failures)

* Try:
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.

* Get more help at https://help.gradle.org

BUILD FAILED in 2s
Running Gradle task 'assembleRelease'... 3.3s

┌─ Flutter Fix ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ The plugin device_info_plus requires a higher Android SDK version. │
│ Fix this issue by adding the following to the file /Users/miaojiangwei/工作/workspace/flutter/flutter_rent_house_demo/android/app/build.gradle: │
│ android { │
│ defaultConfig { │
│ minSdkVersion 19 │
│ } │
│ } │
│ │
│ │
│ Following this change, your app will not be available to users running Android SDKs below 19. │
│ Consider searching for a version of this plugin that supports these lower versions of the Android SDK instead. │
│ For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration │
└───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
Gradle task assembleRelease failed with exit code 1

处理

找到这个文件 /android/app/build.gradle

1
2
3
4
5
6
7
8
9
10
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.example.rent_house"
// You can update the following values to match your application needs.
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
minSdkVersion flutter.minSdkVersion
targetSdkVersion flutter.targetSdkVersion
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
}

minSdkVersion 改为 19

1
2
3
4
5
6
7
8
9
10
11
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.example.rent_house"
// You can update the following values to match your application needs.
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
// minSdkVersion flutter.minSdkVersion
minSdkVersion 19
targetSdkVersion flutter.targetSdkVersion
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
}

flutter run app pods报错

githubclone别人的项目,使用vscode试图去运行debug时诱发的一些问题!

1
error: could not find included file 'Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig' in search paths (in target 'Runner')
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
➜  ios git:(master) ✗ rm -f Podfile
➜ ios git:(master) ✗ ls
Flutter Runner Runner.xcworkspace
Podfile.lock Runner.xcodeproj
➜ ios git:(master) ✗ ls
Flutter Runner Runner.xcworkspace
Podfile.lock Runner.xcodeproj
➜ ios git:(master) ✗ pod install
[!] No `Podfile' found in the project directory.
➜ ios git:(master) ✗ pod init
➜ ios git:(master) ✗ ls
Flutter Podfile.lock Runner.xcodeproj
Podfile Runner Runner.xcworkspace
➜ ios git:(master) ✗ pod install
Analyzing dependencies
Downloading dependencies
Generating Pods project
Integrating client project
Pod installation complete! There are 0 dependencies from the Podfile and 0 total pods installed.

[!] The Podfile does not contain any dependencies.

[!] Automatically assigning platform `iOS` with version `11.0` on target `Runner` because no platform was specified. Please specify a platform for this target in your Podfile. See `https://guides.cocoapods.org/syntax/podfile.html#platform`.

[!] CocoaPods did not set the base configuration of your project because your project already has a custom config set. In order for CocoaPods integration to work at all, please either set the base configurations of the target `Runner` to `Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig` or include the `Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig` in your build configuration (`Flutter/Release.xcconfig`).
➜ ios git:(master) ✗

处理方案

删除 ios/Podfile 重新init初始化下!

1
rm -f ios/Podfile
1
pod init
1
pod install

然后在重新运行下就可以了!