jsbox-cview 1.6.5 → 1.6.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (164) hide show
  1. package/README.md +4 -0
  2. package/dist/components/alert/input-alert.d.ts +22 -0
  3. package/dist/components/alert/input-alert.js +1 -2
  4. package/dist/components/alert/login-alert.d.ts +21 -0
  5. package/dist/components/alert/login-alert.js +1 -2
  6. package/dist/components/alert/plain-alert.d.ts +15 -0
  7. package/dist/components/alert/plain-alert.js +1 -2
  8. package/dist/components/alert/uialert.d.ts +29 -0
  9. package/{components/base.ts → dist/components/base.d.ts} +9 -28
  10. package/dist/components/custom-navigation-bar.d.ts +117 -0
  11. package/dist/components/custom-navigation-bar.js +7 -1
  12. package/dist/components/dialogs/dialog-sheet.d.ts +46 -0
  13. package/dist/components/dialogs/dialog-sheet.js +3 -1
  14. package/dist/components/dialogs/form-dialog.d.ts +15 -0
  15. package/dist/components/dialogs/form-dialog.js +1 -2
  16. package/dist/components/dialogs/list-dialog.d.ts +23 -0
  17. package/dist/components/dialogs/list-dialog.js +2 -3
  18. package/dist/components/dialogs/text-dialog.d.ts +13 -0
  19. package/dist/components/dialogs/text-dialog.js +1 -2
  20. package/dist/components/dynamic-contextmenu-view.d.ts +40 -0
  21. package/dist/components/dynamic-contextmenu-view.js +5 -1
  22. package/dist/components/dynamic-itemsize-matrix.d.ts +79 -0
  23. package/dist/components/dynamic-itemsize-matrix.js +18 -15
  24. package/dist/components/dynamic-itemsize-section-matrix.d.ts +115 -0
  25. package/dist/components/dynamic-itemsize-section-matrix.js +293 -0
  26. package/dist/components/dynamic-preference-listview.d.ts +63 -0
  27. package/dist/components/dynamic-preference-listview.js +25 -16
  28. package/dist/components/dynamic-rowheight-list.d.ts +38 -0
  29. package/dist/components/dynamic-rowheight-list.js +10 -3
  30. package/dist/components/enhanced-imageview.d.ts +41 -0
  31. package/dist/components/enhanced-imageview.js +1 -1
  32. package/dist/components/flowlayout.d.ts +63 -0
  33. package/dist/components/flowlayout.js +10 -13
  34. package/dist/components/image-pager.d.ts +49 -0
  35. package/dist/components/image-pager.js +6 -1
  36. package/dist/components/oc-webview.d.ts +64 -0
  37. package/dist/components/oc-webview.js +13 -5
  38. package/dist/components/page-control.d.ts +45 -0
  39. package/dist/components/page-control.js +2 -13
  40. package/dist/components/pageviewer-titlebar.d.ts +48 -0
  41. package/dist/components/pageviewer-titlebar.js +7 -13
  42. package/dist/components/pageviewer.d.ts +41 -0
  43. package/dist/components/pageviewer.js +4 -1
  44. package/dist/components/refresh-button.d.ts +25 -0
  45. package/dist/components/refresh-button.js +3 -4
  46. package/dist/components/rotating-view.d.ts +45 -0
  47. package/dist/components/rotating-view.js +10 -2
  48. package/dist/components/searchbar.d.ts +118 -0
  49. package/dist/components/searchbar.js +8 -1
  50. package/dist/components/sheet.d.ts +42 -0
  51. package/dist/components/single-views.d.ts +289 -0
  52. package/dist/components/single-views.js +11 -4
  53. package/dist/components/spinners/loading-dual-ring.d.ts +18 -0
  54. package/dist/components/spinners/loading-wedges.d.ts +15 -0
  55. package/dist/components/spinners/spinner-androidstyle.d.ts +30 -0
  56. package/dist/components/spinners/spinner-androidstyle.js +7 -1
  57. package/dist/components/static-preference-listview.d.ts +389 -0
  58. package/dist/components/static-preference-listview.js +13 -10
  59. package/dist/components/symbol-button.d.ts +39 -0
  60. package/dist/components/symbol-button.js +8 -1
  61. package/dist/components/tabbar.d.ts +140 -0
  62. package/dist/components/tabbar.js +8 -1
  63. package/dist/controller/base-controller.d.ts +125 -0
  64. package/dist/controller/base-controller.js +11 -11
  65. package/dist/controller/controller-router.d.ts +48 -0
  66. package/dist/controller/pageviewer-controller.d.ts +38 -0
  67. package/dist/controller/pageviewer-controller.js +4 -1
  68. package/dist/controller/presented-page-controller.d.ts +41 -0
  69. package/dist/controller/presented-page-controller.js +7 -9
  70. package/dist/controller/splitview-controller.d.ts +90 -0
  71. package/dist/controller/splitview-controller.js +27 -11
  72. package/dist/controller/tabbar-controller.d.ts +49 -0
  73. package/dist/controller/tabbar-controller.js +12 -15
  74. package/{index.ts → dist/index.d.ts} +2 -0
  75. package/dist/index.js +2 -0
  76. package/dist/utils/colors.d.ts +7 -0
  77. package/dist/utils/cvid.d.ts +11 -0
  78. package/dist/utils/l10n.d.ts +1 -0
  79. package/dist/utils/l10n.js +1 -2
  80. package/dist/utils/path.d.ts +8 -0
  81. package/dist/utils/path.js +8 -9
  82. package/dist/utils/rect.d.ts +38 -0
  83. package/dist/utils/rect.js +8 -9
  84. package/dist/utils/uitools.d.ts +75 -0
  85. package/dist/utils/uitools.js +6 -6
  86. package/package.json +20 -5
  87. package/.prettierignore +0 -6
  88. package/.prettierrc +0 -3
  89. package/components/alert/input-alert.ts +0 -64
  90. package/components/alert/login-alert.ts +0 -66
  91. package/components/alert/plain-alert.ts +0 -39
  92. package/components/alert/uialert.ts +0 -107
  93. package/components/custom-navigation-bar.ts +0 -579
  94. package/components/dialogs/dialog-sheet.ts +0 -111
  95. package/components/dialogs/form-dialog.ts +0 -63
  96. package/components/dialogs/list-dialog.ts +0 -119
  97. package/components/dialogs/text-dialog.ts +0 -44
  98. package/components/dynamic-contextmenu-view.ts +0 -115
  99. package/components/dynamic-itemsize-matrix.ts +0 -206
  100. package/components/dynamic-preference-listview.ts +0 -684
  101. package/components/dynamic-rowheight-list.ts +0 -77
  102. package/components/enhanced-imageview.ts +0 -132
  103. package/components/flowlayout.ts +0 -248
  104. package/components/image-pager.ts +0 -180
  105. package/components/oc-webview.ts +0 -177
  106. package/components/page-control.ts +0 -93
  107. package/components/pageviewer-titlebar.ts +0 -166
  108. package/components/pageviewer.ts +0 -125
  109. package/components/refresh-button.ts +0 -83
  110. package/components/rotating-view.ts +0 -133
  111. package/components/searchbar.ts +0 -398
  112. package/components/sheet.ts +0 -104
  113. package/components/single-views.ts +0 -956
  114. package/components/spinners/loading-dual-ring.ts +0 -97
  115. package/components/spinners/loading-wedges.ts +0 -106
  116. package/components/spinners/spinner-androidstyle.ts +0 -269
  117. package/components/static-preference-listview.ts +0 -1282
  118. package/components/symbol-button.ts +0 -108
  119. package/components/tabbar.ts +0 -453
  120. package/controller/base-controller.ts +0 -214
  121. package/controller/controller-router.ts +0 -73
  122. package/controller/pageviewer-controller.ts +0 -93
  123. package/controller/presented-page-controller.ts +0 -76
  124. package/controller/splitview-controller.ts +0 -359
  125. package/controller/tabbar-controller.ts +0 -131
  126. package/dist/test/custom-navigation-bar.js +0 -40
  127. package/dist/test/dialog-sheet.js +0 -40
  128. package/dist/test/dynamic-contextmenu-view.js +0 -66
  129. package/dist/test/dynamic-itemsize-matrix.js +0 -74
  130. package/dist/test/dynamic-preference-listview.js +0 -150
  131. package/dist/test/flowlayout.js +0 -76
  132. package/dist/test/form-dialog.js +0 -51
  133. package/dist/test/oc-webview.js +0 -195
  134. package/dist/test/pageviewer-controller.js +0 -20
  135. package/dist/test/pageviewer-titlebar.js +0 -18
  136. package/dist/test/pageviewer.js +0 -32
  137. package/dist/test/refresh-button.js +0 -26
  138. package/dist/test/searchbar.js +0 -36
  139. package/dist/test/splitview-controller.js +0 -41
  140. package/dist/test/static-preference-listview.js +0 -143
  141. package/dist/test/tabbar-controller.js +0 -48
  142. package/test/custom-navigation-bar.ts +0 -40
  143. package/test/dialog-sheet.ts +0 -40
  144. package/test/dynamic-contextmenu-view.ts +0 -67
  145. package/test/dynamic-itemsize-matrix.ts +0 -74
  146. package/test/dynamic-preference-listview.ts +0 -151
  147. package/test/flowlayout.ts +0 -79
  148. package/test/form-dialog.ts +0 -48
  149. package/test/oc-webview.ts +0 -197
  150. package/test/pageviewer-controller.ts +0 -21
  151. package/test/pageviewer-titlebar.ts +0 -18
  152. package/test/pageviewer.ts +0 -31
  153. package/test/refresh-button.ts +0 -26
  154. package/test/searchbar.ts +0 -38
  155. package/test/splitview-controller.ts +0 -42
  156. package/test/static-preference-listview.ts +0 -142
  157. package/test/tabbar-controller.ts +0 -49
  158. package/tsconfig.json +0 -122
  159. package/utils/colors.ts +0 -17
  160. package/utils/cvid.ts +0 -32
  161. package/utils/l10n.ts +0 -42
  162. package/utils/path.ts +0 -97
  163. package/utils/rect.ts +0 -90
  164. package/utils/uitools.ts +0 -122
@@ -1,111 +0,0 @@
1
- import { Sheet } from "../sheet";
2
-
3
- import { CustomNavigationBar } from "../custom-navigation-bar";
4
- import { l10n } from "../../utils/l10n";
5
- import { ContentView } from "../single-views";
6
- import { Base } from "../base";
7
-
8
- /**
9
- * dialog所需要的sheet
10
- *
11
- * @param title 标题
12
- * @param cview 内容视图
13
- * @param doneHandler 完成时的回调
14
- * @param presentMode 显示模式
15
- * @param bgcolor 背景颜色
16
- * @param doneButtonHidden 是否隐藏完成按钮, 默认为false,如果隐藏则需要自行实现完成逻辑
17
- * @param doneButtonValidator 完成按钮验证器,返回true则执行完成逻辑,返回false则不执行
18
- * @param doneButtonTitle 完成按钮标题,默认为"完成"
19
- */
20
- export class DialogSheet extends Sheet<ContentView, UIView, UiTypes.ViewOptions> {
21
- _props: {
22
- title: string;
23
- cview: Base<any, any>;
24
- doneHandler?: () => any;
25
- presentMode?: number;
26
- bgcolor?: UIColor;
27
- doneButtonHidden?: boolean;
28
- doneButtonValidator?: () => boolean;
29
- doneButtonTitle?: string;
30
- };
31
- _done: boolean;
32
- private _navbar?: CustomNavigationBar;
33
- resolve?: (value: any) => void;
34
- reject?: (reason: any) => void;
35
-
36
- constructor(props: {
37
- title: string;
38
- cview: Base<any, any>;
39
- doneHandler?: () => any;
40
- presentMode?: number;
41
- bgcolor?: UIColor;
42
- doneButtonHidden?: boolean;
43
- doneButtonValidator?: () => boolean;
44
- doneButtonTitle?: string;
45
- }) {
46
- super({
47
- presentMode: props.presentMode || ($device.isIpad ? 2 : 1),
48
- bgcolor: props.bgcolor,
49
- });
50
- this._props = props;
51
- this._done = false;
52
- }
53
-
54
- promisify(resolve: (value: any) => void, reject: (reason: any) => void) {
55
- this.resolve = resolve;
56
- this.reject = reject;
57
- }
58
-
59
- present() {
60
- this._dismissalHandler = () => {
61
- if (!this._done && this.reject) this.reject("cancel");
62
- };
63
- this._navbar = new CustomNavigationBar({
64
- props: {
65
- title: this._props.title,
66
- leftBarButtonItems: [{ symbol: "xmark", handler: () => this.dismiss() }],
67
- rightBarButtonItems: this._props.doneButtonHidden
68
- ? []
69
- : [
70
- {
71
- title: this._props.doneButtonTitle || l10n("DONE"),
72
- handler: () => {
73
- if (this._props.doneButtonValidator) {
74
- if (this._props.doneButtonValidator()) {
75
- this.done();
76
- } else {
77
- return;
78
- }
79
- }
80
- this.done();
81
- },
82
- },
83
- ],
84
- },
85
- });
86
- this._props.cview._layout = (make, view) => {
87
- make.left.right.bottom.equalTo(view.super);
88
- make.top.equalTo(view.prev.bottom);
89
- };
90
- this._cview = new ContentView({
91
- props: { bgcolor: $color("clear") },
92
- views: [this._navbar.definition, this._props.cview.definition],
93
- });
94
- super.present();
95
- }
96
-
97
- done() {
98
- this._done = true;
99
- if (this.resolve && this._props.doneHandler) this.resolve(this._props.doneHandler());
100
- this.dismiss();
101
- }
102
-
103
- get title() {
104
- return this._props.title;
105
- }
106
-
107
- set title(title: string) {
108
- this._props.title = title;
109
- if (this._navbar) this._navbar.title = title;
110
- }
111
- }
@@ -1,63 +0,0 @@
1
- import { Base } from "../base";
2
- import { PreferenceListView, PreferenceSection } from "../static-preference-listview";
3
- import { DialogSheet } from "./dialog-sheet";
4
-
5
- class DialogSheetForm extends DialogSheet {
6
- private _checkHandler: (values: { [key: string]: any }) => boolean;
7
- constructor(
8
- sheetProps: {
9
- title: string;
10
- cview: Base<any, any>;
11
- doneHandler?: () => void;
12
- presentMode?: number;
13
- bgcolor?: UIColor;
14
- doneButtonHidden?: boolean;
15
- },
16
- checkHandler: (values: { [key: string]: any }) => boolean,
17
- ) {
18
- super(sheetProps);
19
- this._checkHandler = checkHandler;
20
- }
21
-
22
- done() {
23
- if (this.resolve && this._props.doneHandler) {
24
- const values = this._props.doneHandler();
25
- const success = this._checkHandler(values);
26
- if (success) {
27
- this._done = true;
28
- this.resolve(values);
29
- this.dismiss();
30
- }
31
- }
32
- }
33
- }
34
-
35
- /**
36
- * 显示一个表单
37
- * @param sections 表单分组, 请参考`PreferenceListView`中的`PreferenceSection`
38
- * @param title 标题
39
- */
40
- export function formDialog({
41
- sections,
42
- title,
43
- checkHandler,
44
- }: {
45
- sections: PreferenceSection[];
46
- title: string;
47
- checkHandler?: (values: { [key: string]: any }) => boolean;
48
- }): Promise<{ [key: string]: any }> {
49
- const view = new PreferenceListView({ sections });
50
- const sheet = new DialogSheetForm(
51
- {
52
- title,
53
- bgcolor: $color("insetGroupedBackground"),
54
- cview: view,
55
- doneHandler: () => view.values,
56
- },
57
- checkHandler || (() => true),
58
- );
59
- return new Promise((resolve, reject) => {
60
- sheet.promisify(resolve, reject);
61
- sheet.present();
62
- });
63
- }
@@ -1,119 +0,0 @@
1
- import { DialogSheet } from "./dialog-sheet";
2
- import { List } from "../single-views";
3
-
4
- /**
5
- * 显示一个列表以供选择
6
- *
7
- * @param items 选项
8
- * @param multiSelectEnabled 是否允许多选
9
- * @param value 默认选中的选项
10
- * @param values 默认选中的选项, 配合multiSelectEnabled使用
11
- * @param title 标题
12
- */
13
- export function listDialog({
14
- items,
15
- multiSelectEnabled,
16
- value,
17
- values,
18
- title,
19
- }: {
20
- items: string[];
21
- multiSelectEnabled: true;
22
- value?: never;
23
- values?: number[];
24
- title: string;
25
- }): Promise<number[]>;
26
- export function listDialog({
27
- items,
28
- multiSelectEnabled,
29
- value,
30
- values,
31
- title,
32
- }: {
33
- items: string[];
34
- multiSelectEnabled?: false | undefined;
35
- value?: number;
36
- values?: never;
37
- title: string;
38
- }): Promise<number>;
39
- export function listDialog({
40
- items,
41
- multiSelectEnabled,
42
- value,
43
- values = [],
44
- title,
45
- }: {
46
- items: string[];
47
- multiSelectEnabled?: boolean;
48
- value?: number;
49
- values?: number[];
50
- title: string;
51
- }): Promise<number | number[]> {
52
- if (value) values = [value];
53
- const listView = new List({
54
- props: {
55
- style: 2,
56
- data: items.map((n, i) => {
57
- return {
58
- label: { text: n },
59
- image: { hidden: !values.includes(i) },
60
- };
61
- }),
62
- template: {
63
- views: [
64
- {
65
- type: "label",
66
- props: {
67
- id: "label",
68
- },
69
- layout: (make, view) => {
70
- make.top.bottom.inset(0);
71
- make.left.inset(20);
72
- make.right.inset(50);
73
- },
74
- },
75
- {
76
- type: "image",
77
- props: {
78
- id: "image",
79
- symbol: "checkmark",
80
- contentMode: 1,
81
- tintColor: $color("systemLink"),
82
- },
83
- layout: (make, view) => {
84
- make.top.bottom.right.inset(10);
85
- make.width.equalTo(30);
86
- },
87
- },
88
- ],
89
- },
90
- },
91
- events: {
92
- didSelect: (sender, indexPath) => {
93
- const data = sender.data;
94
- if (multiSelectEnabled) {
95
- data[indexPath.item].image.hidden = !data[indexPath.item].image.hidden;
96
- } else {
97
- data.forEach((n, i) => {
98
- n.image.hidden = i !== indexPath.item;
99
- });
100
- }
101
- sender.data = data;
102
- },
103
- },
104
- });
105
- const sheet = new DialogSheet({
106
- title,
107
- bgcolor: $color("insetGroupedBackground"),
108
- cview: listView,
109
- doneHandler: () => {
110
- const filtered = listView.view.data.map((n, i) => (n.image.hidden ? -1 : i)).filter((n) => n !== -1);
111
- if (multiSelectEnabled) return filtered;
112
- else return filtered[0];
113
- },
114
- });
115
- return new Promise((resolve, reject) => {
116
- sheet.promisify(resolve, reject);
117
- sheet.present();
118
- });
119
- }
@@ -1,44 +0,0 @@
1
- import { Text } from "../single-views";
2
- import { DialogSheet } from "./dialog-sheet";
3
-
4
- /**
5
- * 返回一个Promise用于输入文本
6
- * @param title 标题
7
- * @param text 初始文本
8
- * @param placeholder 占位符
9
- * @param editable 是否可编辑
10
- */
11
- export function textDialog({
12
- title,
13
- text = "",
14
- placeholder = "",
15
- editable = true,
16
- }: {
17
- title: string;
18
- text?: string;
19
- placeholder?: string;
20
- editable?: boolean;
21
- }): Promise<string> {
22
- const textView = new Text({
23
- props: {
24
- text,
25
- placeholder,
26
- editable,
27
- },
28
- events: {
29
- ready: (sender) => {
30
- if (sender.editable) sender.focus();
31
- },
32
- },
33
- });
34
-
35
- const sheet = new DialogSheet({
36
- title,
37
- cview: textView,
38
- doneHandler: () => textView.view.text,
39
- });
40
- return new Promise((resolve, reject) => {
41
- sheet.promisify(resolve, reject);
42
- sheet.present();
43
- });
44
- }
@@ -1,115 +0,0 @@
1
- import { Base } from "./base";
2
- import { cvid } from "../utils/cvid";
3
-
4
- type MenuItem = {
5
- title: string;
6
- symbol?: string;
7
- handler: () => void;
8
- destructive?: boolean;
9
- };
10
-
11
- const RegisteredOCClassName: Set<string> = new Set();
12
-
13
- /**
14
- * 动态上下文菜单视图,此视图是为了弥补JSBox中无法动态调整上下文菜单的缺陷而设计的。
15
- *
16
- * 此视图除了一般UIView的props, layout, events, views四个参数外,还有必须的特殊参数:
17
- * 1. classname?: string OC类名,如果不指定则会自动生成一个唯一的类名。
18
- * 如果有不同的DynamicContextMenuView实例使用相同的OC类,
19
- * 那么无法确定弹出的contextMenu是绑定了哪个实例。
20
- * 换言之,实例A弹出的Menu可能是绑定的实例B。
21
- * 如果这样做,必须使用下面generateContextMenu的sender参数来定位。
22
- * 2. generateContextMenu: (sender: UIView) => { title: string; items: MenuItem[]; }
23
- * 生成上下文菜单的回调函数。
24
- *
25
- */
26
- export class DynamicContextMenuView extends Base<UIView, UiTypes.RuntimeOptions> {
27
- private generateContextMenu: (sender: UIView) => {
28
- title?: string;
29
- items: MenuItem[];
30
- };
31
- private _ocClassName: string;
32
- _defineView: () => UiTypes.RuntimeOptions;
33
-
34
- constructor({
35
- classname,
36
- generateContextMenu,
37
- props,
38
- layout,
39
- events,
40
- views,
41
- }: {
42
- classname?: string;
43
- generateContextMenu: (sender: UIView) => {
44
- title?: string;
45
- items: MenuItem[];
46
- };
47
- props: UiTypes.ViewProps;
48
- layout?: (make: MASConstraintMaker, view: UIView) => void;
49
- events?: UiTypes.BaseViewEvents;
50
- views?: UiTypes.AllViewOptions[];
51
- }) {
52
- super();
53
- this._ocClassName = classname || `DynamicContextMenuView_${cvid.newId}`;
54
- this.generateContextMenu = generateContextMenu;
55
- const runtimeView = this.createRuntimeView();
56
- this._defineView = () => {
57
- return {
58
- type: "runtime",
59
- props: {
60
- ...props,
61
- id: this.id,
62
- view: runtimeView,
63
- },
64
- layout,
65
- events,
66
- views,
67
- };
68
- };
69
- }
70
-
71
- private defineOCClass() {
72
- if (RegisteredOCClassName.has(this._ocClassName)) return;
73
- RegisteredOCClassName.add(this._ocClassName);
74
- $define({
75
- type: this._ocClassName + " : UIView <UIContextMenuInteractionDelegate>",
76
- events: {
77
- "contextMenuInteraction:configurationForMenuAtLocation:": (interacton: any, point: JBPoint) => {
78
- const view = interacton.$view().jsValue();
79
- const menu = this.generateContextMenu(view);
80
- return this.createContextMenuConfiguration(menu);
81
- },
82
- },
83
- });
84
- }
85
-
86
- private createContextMenuConfiguration({ title, items }: { title?: string; items: MenuItem[] }) {
87
- return $objc("UIContextMenuConfiguration").$configurationWithIdentifier_previewProvider_actionProvider(
88
- null,
89
- null,
90
- $block("UIMenu *, NSArray *", () => {
91
- const actions = items.map((item) => {
92
- const action = $objc("UIAction").$actionWithTitle_image_identifier_handler(
93
- item.title,
94
- item.symbol || null,
95
- null,
96
- $block("void, UIAction *", () => item.handler()),
97
- );
98
- if (item.destructive) action.$setAttributes(1 << 1);
99
- return action;
100
- });
101
- return title
102
- ? $objc("UIMenu").$menuWithTitle_children(title, actions)
103
- : $objc("UIMenu").$menuWithChildren(actions);
104
- }),
105
- );
106
- }
107
-
108
- private createRuntimeView() {
109
- this.defineOCClass();
110
- const view = $objc(this._ocClassName).invoke("alloc.init");
111
- const interaction = $objc("UIContextMenuInteraction").invoke("alloc").invoke("initWithDelegate", view);
112
- view.$addInteraction(interaction);
113
- return view;
114
- }
115
- }
@@ -1,206 +0,0 @@
1
- import { Base } from "./base";
2
- import { Matrix } from "./single-views";
3
-
4
- interface DynamicItemSizeMatrixProps extends UiTypes.MatrixProps {
5
- fixedItemHeight: number;
6
- minItemWidth: number;
7
- maxColumns: number;
8
- spacing: number;
9
- dynamicHeightEnabled?: boolean;
10
- }
11
-
12
- interface DynamicItemSizeMatrixEvents extends UiTypes.MatrixEvents {
13
- itemHeight?: (width: number) => number;
14
- heightChanged?: (sender: DynamicItemSizeMatrix, height: number) => void;
15
- }
16
-
17
- interface DynamicItemSizeMatrixPropsPartial extends UiTypes.MatrixProps {
18
- fixedItemHeight?: number;
19
- minItemWidth?: number;
20
- maxColumns?: number;
21
- spacing?: number;
22
- dynamicHeightEnabled?: boolean;
23
- }
24
-
25
- function _getColumnsAndItemSizeWidth(
26
- containerWidth: number,
27
- minItemWidth: number,
28
- maxColumns: number,
29
- spacing: number,
30
- ) {
31
- if (minItemWidth > containerWidth - 2 * spacing) {
32
- return {
33
- columns: 1,
34
- itemSizeWidth: containerWidth - 2 * spacing,
35
- };
36
- }
37
- const columns = Math.max(
38
- Math.min(Math.floor((containerWidth - spacing) / (minItemWidth + spacing)), maxColumns),
39
- 1, // 最少一列
40
- );
41
- const itemSizeWidth = Math.max(
42
- Math.floor((containerWidth - spacing * (columns + 1)) / columns),
43
- minItemWidth, // 最小宽度
44
- );
45
- return {
46
- columns,
47
- itemSizeWidth,
48
- };
49
- }
50
-
51
- /**
52
- * # CView Dynamic ItemSize Matrix
53
- *
54
- * 此组件是为了解决让 Matrix 的 ItemSize 跟随重新布局而动态变化的问题
55
- *
56
- * 动态的改变自己的 itemSize,从而使得 spacing 被优先满足。
57
- * 思路为在 matrix 上层套一个 superView,在旋转的时候 superView 会调用 matrix.relayout()
58
- * 和 matrix.reload(),从而触发 itemSize 事件
59
- *
60
- * 此视图的高度可以自动调整,需要 dynamicHeightEnabled 设为 true,且 layout 中要有关于 height 的约束
61
- *
62
- * 其排布逻辑是这样的:
63
- *
64
- * 1. 由 minItemWidth,spacing,maxColumns 这三个参数决定 cloumns,
65
- * 并结合 totalWidth 确定 itemSize.width
66
- * 2. 确定 itemHeight 有两种方法:
67
- * - fixedItemHeight 固定高度,优先级第二
68
- * - event: itemHeight(width) => height 通过 width 动态计算,优先级最高
69
- * 3. 如果 minItemWidth 比 totalWidth - 2 * spacing 还要小,那么 itemSize.width
70
- * 会被设定为 totalWidth - 2 * spacing,以保证item不会超出边框
71
- *
72
- * props:
73
- *
74
- * 可以使用 matrix 的全部属性
75
- *
76
- * 特殊属性:
77
- *
78
- * - fixedItemHeight 固定 itemSize 高度
79
- * - minItemWidth 最小的 itemSize 宽度
80
- * - maxColumns 最大列数
81
- * - spacing
82
- * - dynamicHeightEnabled 此项为 true,那么 scrollEnabled 自动设为 false,且高度可以自动调整
83
- *
84
- * events:
85
- *
86
- * 可以使用 matrix 除 itemSize 以外的全部事件
87
- *
88
- * 其他特殊事件:
89
- *
90
- * - itemHeight: width => height 通过 itemWidth 动态计算 itemHeight
91
- *
92
- *
93
- * 方法:
94
- * - heightToWidth(width) 计算特定width时的应有的高度
95
- */
96
- export class DynamicItemSizeMatrix extends Base<UIView, UiTypes.ViewOptions> {
97
- private _props: DynamicItemSizeMatrixProps;
98
- private _events: DynamicItemSizeMatrixEvents;
99
- private _itemSizeWidth: number;
100
- private _itemSizeHeight: number;
101
- private _totalWidth: number = 0;
102
- private _columns: number = 1;
103
- matrix: Matrix;
104
- _defineView: () => UiTypes.ViewOptions;
105
-
106
- constructor({
107
- props,
108
- layout,
109
- events = {},
110
- }: {
111
- props: DynamicItemSizeMatrixPropsPartial;
112
- layout: (make: MASConstraintMaker, view: UIView) => void;
113
- events: DynamicItemSizeMatrixEvents;
114
- }) {
115
- super();
116
- this._props = {
117
- fixedItemHeight: 40,
118
- minItemWidth: 96,
119
- maxColumns: 5,
120
- spacing: 6,
121
- dynamicHeightEnabled: false,
122
- ...props,
123
- };
124
- this._events = events;
125
- const { itemHeight, heightChanged, ...rest } = this._events;
126
- const _matrixEvents = rest;
127
- this._itemSizeWidth = 0;
128
- this._itemSizeHeight = 0;
129
- this.matrix = new Matrix({
130
- props: {
131
- ...this._props,
132
- scrollEnabled: !this._props.dynamicHeightEnabled,
133
- },
134
- layout: $layout.fill,
135
- events: {
136
- ..._matrixEvents,
137
- itemSize: (sender) => $size(this._itemSizeWidth, this._itemSizeHeight),
138
- },
139
- });
140
- this._defineView = () => {
141
- return {
142
- type: "view",
143
- props: {
144
- bgcolor: $color("clear"),
145
- id: this.id,
146
- },
147
- layout,
148
- events: {
149
- layoutSubviews: (sender) => {
150
- sender.relayout();
151
- if (sender.frame.width === this._totalWidth) return;
152
- const { columns, itemSizeWidth } = _getColumnsAndItemSizeWidth(
153
- sender.frame.width,
154
- this._props.minItemWidth,
155
- this._props.maxColumns,
156
- this._props.spacing,
157
- );
158
- this._columns = columns;
159
- this._itemSizeWidth = itemSizeWidth;
160
- this._itemSizeHeight = this._events.itemHeight
161
- ? this._events.itemHeight(this._itemSizeWidth)
162
- : this._props.fixedItemHeight;
163
- this.matrix.view.reload();
164
- if (this._props.dynamicHeightEnabled) {
165
- const height = this.heightToWidth(sender.frame.width);
166
- sender.updateLayout((make) => make.height.equalTo(height));
167
- if (this._events.heightChanged) this._events.heightChanged(this, height);
168
- }
169
- },
170
- },
171
- views: [this.matrix.definition],
172
- };
173
- };
174
- }
175
-
176
- heightToWidth(width: number) {
177
- const { columns, itemSizeWidth } = _getColumnsAndItemSizeWidth(
178
- width,
179
- this._props.minItemWidth,
180
- this._props.maxColumns,
181
- this._props.spacing,
182
- );
183
- const rows = this._props.data ? Math.ceil(this._props.data.length / columns) : 0;
184
- const itemSizeHeight = this._events.itemHeight
185
- ? this._events.itemHeight(itemSizeWidth)
186
- : this._props.fixedItemHeight;
187
- return rows * itemSizeHeight + (rows + 1) * this._props.spacing;
188
- }
189
-
190
- get data() {
191
- return this.matrix.view.data;
192
- }
193
-
194
- set data(data) {
195
- this._props.data = data;
196
- this.matrix.view.data = data;
197
- }
198
-
199
- get columns() {
200
- return this._columns;
201
- }
202
-
203
- get itemSize() {
204
- return $size(this._itemSizeWidth, this._itemSizeHeight);
205
- }
206
- }