SafeView.ets 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. import { WindowHelper } from '../utils/WindowHelper';
  2. import { inputMethod } from '@kit.IMEKit';
  3. import { ToolsHelper } from '../utils/ToolsHelper';
  4. export interface TitleBarBtn {
  5. text?: string | Resource;
  6. img?: PixelMap | ResourceStr | DrawableDescriptor;
  7. color?: string | Resource;
  8. onClick: () => void
  9. }
  10. @Component
  11. export struct SafeView {
  12. pageInfos?: NavPathStack
  13. @Prop isLoading: boolean
  14. // 是不是沉浸式
  15. @Prop isImmersive: boolean
  16. // 设置导航栏标题
  17. @Prop titleText: ResourceStr
  18. // 设置导航栏标题颜色
  19. @Prop titleColor: ResourceColor
  20. // 设置导航栏背景色
  21. @Prop backgroundColorNav: ResourceColor
  22. // 设置导航栏背景色
  23. @Prop backgroundColorView: ResourceColor
  24. // 设置导航栏背景不透明度
  25. // 元素的不透明度,取值范围为0到1,1表示不透明,0表示完全透明, 达到隐藏组件效果,但是在布局中占位。
  26. @Prop opacitys: number | Resource
  27. // 是否显示返回按钮
  28. @Prop hideBack: boolean
  29. // 物理返回按键是否需要双击触发
  30. @Prop doubleBack: boolean
  31. // 是否显示浅色返回按钮
  32. @Prop lightBack: boolean
  33. // 是否显示导航栏
  34. @Prop hideNavBar: boolean
  35. /**
  36. * 是否显示左侧角标,存在onClickLeft时生效
  37. */
  38. @Prop showBadgeLeft: boolean;
  39. /**
  40. * 是否显示右侧角标,存在onClickLeft时生效
  41. */
  42. @Prop showBadgeRight: boolean;
  43. // 设置返回按钮事件,如果hideBack为true,该事件无效
  44. onBackEvent?: () => void
  45. // 设置导航栏点击事件
  46. @Prop onClickLeft: TitleBarBtn
  47. @Prop onClickRight: TitleBarBtn
  48. // 设置导航栏底下标题
  49. @Prop bottomTitleText: ResourceStr
  50. @Builder
  51. doNothingBuilder() {
  52. }
  53. @BuilderParam customBuilderParam: () => void = this.doNothingBuilder
  54. build() {
  55. NavDestination() {
  56. Stack() {
  57. Column() {
  58. this.customBuilderParam()
  59. }
  60. .padding({
  61. // 沉浸式直接0,如果给值的话,会造成用户ui无法覆盖状态栏
  62. top: this.isImmersive ? 0 : this.hideNavBar ? 44 : WindowHelper.topRectHeight + 44,
  63. bottom: this.isImmersive ? 0 : WindowHelper.bottomRectHeight
  64. })
  65. .align(Alignment.Top)
  66. .width('100%')
  67. .height('100%')
  68. if (!this.hideNavBar) {
  69. Row()
  70. .height(WindowHelper.topRectHeight)
  71. .width('100%')
  72. .backgroundColor(this.backgroundColorNav ?? '#ffffff')
  73. .opacity(undefined === this.opacitys ? 1 : this.opacitys > 1 ? 1 : this.opacitys < 0 ? 0 : this.opacitys)
  74. Row() {
  75. Row() {
  76. Image(this.lightBack ? $r("app.media.base_back_light") : $r("app.media.base_back"))
  77. .height(15)
  78. .objectFit(ImageFit.Contain).visibility(!this.hideBack ? Visibility.Visible : Visibility.None)
  79. }.width(110).height(44).alignItems(VerticalAlign.Center)
  80. .onClick(() => {
  81. if (this.hideBack) {
  82. return
  83. }
  84. if (this.onBackEvent && !this.hideBack) {
  85. this.onBackEvent()
  86. } else if (this.pageInfos) {
  87. this.pageInfos.pop()
  88. }
  89. })
  90. Column() {
  91. Text(this.titleText ?? '')
  92. .maxLines(1)
  93. .fontColor(this.titleColor ?? '#11102C')
  94. .fontSize(16)
  95. .fontWeight(FontWeight.Medium)
  96. .ellipsisMode(EllipsisMode.CENTER)
  97. .textOverflow({
  98. overflow: TextOverflow.Ellipsis
  99. })
  100. .constraintSize({
  101. maxWidth: 200
  102. })
  103. if (this.bottomTitleText) {
  104. Text(this.bottomTitleText ?? '').fontColor('#CB8204').fontSize(12).margin({ top: 4 })
  105. }
  106. }
  107. Row() {
  108. if (!this.onClickLeft?.img && this.onClickLeft) {
  109. Badge({
  110. count: this.showBadgeLeft ? 1 : 0,
  111. style: {
  112. badgeSize: 6,
  113. badgeColor: Color.Red,
  114. fontSize: 1,
  115. color: '#FF6500',
  116. }
  117. }) {
  118. Text(`${this.onClickLeft?.text}` ?? '确定')
  119. .fontColor(this.onClickLeft?.color ?? '#17171A')
  120. .onClick(() => {
  121. this.onClickLeft?.onClick && this.onClickLeft?.onClick()
  122. })
  123. }
  124. }
  125. if (this.onClickLeft?.img && this.onClickLeft) {
  126. Badge({
  127. count: this.showBadgeLeft ? 1 : 0,
  128. style: {
  129. badgeSize: 6,
  130. badgeColor: '#FF6500',
  131. color: '#FF6500',
  132. fontSize: 1
  133. }
  134. }) {
  135. Image(this.onClickLeft.img)
  136. .onClick(() => {
  137. this.onClickLeft?.onClick && this.onClickLeft?.onClick()
  138. })
  139. .objectFit(ImageFit.Contain)
  140. .width(20)
  141. .height(20)
  142. }
  143. }
  144. if (!this.onClickRight?.img && this.onClickRight) {
  145. Badge({
  146. count: this.showBadgeRight ? 1 : 0,
  147. style: {
  148. badgeSize: 6,
  149. badgeColor: '#FF6500',
  150. color: '#FF6500',
  151. fontSize: 1
  152. }
  153. }) {
  154. Text(this.onClickRight?.text ?? '确定')
  155. .fontColor(this.onClickRight?.color ?? '#17171A')
  156. .onClick(() => {
  157. this.onClickRight?.onClick && this.onClickRight?.onClick()
  158. })
  159. .margin({
  160. left: 10
  161. })
  162. }
  163. }
  164. if (this.onClickRight?.img && this.onClickRight) {
  165. Badge({
  166. count: this.showBadgeRight ? 1 : 0,
  167. style: {
  168. badgeSize: 6,
  169. badgeColor: '#FF6500',
  170. color: '#FF6500',
  171. fontSize: 1
  172. }
  173. }) {
  174. Image(this.onClickRight.img)
  175. .onClick(() => {
  176. this.onClickRight?.onClick && this.onClickRight?.onClick()
  177. })
  178. .objectFit(ImageFit.Contain)
  179. .width(20)
  180. .height(20)
  181. .margin({
  182. left: 10
  183. })
  184. }
  185. }
  186. }.width(110)
  187. .justifyContent(FlexAlign.End)
  188. }
  189. .backgroundColor(this.backgroundColorNav ?? '#ffffff')
  190. .opacity(undefined === this.opacitys ? 1 : this.opacitys > 1 ? 1 : this.opacitys < 0 ? 0 : this.opacitys)
  191. .justifyContent(FlexAlign.SpaceBetween)
  192. .height(44)
  193. .padding({
  194. left: 15,
  195. right: 15
  196. })
  197. .width('100%')
  198. .margin({
  199. top: WindowHelper.topRectHeight
  200. })
  201. }
  202. Column() {
  203. LoadingProgress()
  204. .color(Color.White)
  205. .width(80).height(80)
  206. Text('努力加载中..')
  207. .fontSize(16)
  208. .fontColor(Color.White)
  209. }
  210. .visibility(this.isLoading ? Visibility.Visible : Visibility.None)
  211. .width('100%')
  212. .height('100%')
  213. .backgroundColor('#40000000')
  214. .justifyContent(FlexAlign.Center)
  215. }
  216. .align(Alignment.Top)
  217. .width('100%')
  218. .height('100%')
  219. }
  220. .onClick(() => {
  221. inputMethod.getController().stopInputSession()
  222. })
  223. .hideTitleBar(true)
  224. .width('100%')
  225. .height('100%')
  226. .backgroundColor(this.backgroundColorView ?? '#ffffff')
  227. .onBackPressed(() => {
  228. if (this.onBackEvent) {
  229. if (this.doubleBack) {
  230. const t = this.onBackEvent
  231. ToolsHelper.doubleAndExit(() => {
  232. t()
  233. })
  234. } else {
  235. this.onBackEvent()
  236. }
  237. return true
  238. } else if (this.pageInfos) {
  239. if (this.doubleBack) {
  240. const t = this.pageInfos
  241. ToolsHelper.doubleAndExit(() => {
  242. t.pop()
  243. })
  244. } else {
  245. this.pageInfos.pop()
  246. }
  247. return true
  248. } else {
  249. return false
  250. }
  251. })
  252. }
  253. }