@nativescript/core 9.0.0-next-09-24-2025-17985801416 → 9.0.0-next-10-06-2025-18277360121

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 (181) hide show
  1. package/inspector_modules.js +74 -47
  2. package/inspector_modules.js.map +1 -1
  3. package/package.json +1 -1
  4. package/platforms/android/include.gradle +51 -0
  5. package/platforms/android/java/org/nativescript/Process.java +59 -0
  6. package/platforms/android/java/org/nativescript/widgets/AbsoluteLayout.java +88 -0
  7. package/platforms/android/java/org/nativescript/widgets/AnimatorHelper.java +61 -0
  8. package/platforms/android/java/org/nativescript/widgets/Async.java +1356 -0
  9. package/platforms/android/java/org/nativescript/widgets/BorderDrawable.java +936 -0
  10. package/platforms/android/java/org/nativescript/widgets/BottomNavigationBar.java +308 -0
  11. package/platforms/android/java/org/nativescript/widgets/BoxShadowDrawable.java +175 -0
  12. package/platforms/android/java/org/nativescript/widgets/CSSValue.java +34 -0
  13. package/platforms/android/java/org/nativescript/widgets/CommonLayoutParams.java +456 -0
  14. package/platforms/android/java/org/nativescript/widgets/ContentLayout.java +85 -0
  15. package/platforms/android/java/org/nativescript/widgets/CustomTransition.java +135 -0
  16. package/platforms/android/java/org/nativescript/widgets/CustomTypefaceSpan.java +44 -0
  17. package/platforms/android/java/org/nativescript/widgets/Dock.java +15 -0
  18. package/platforms/android/java/org/nativescript/widgets/DockLayout.java +185 -0
  19. package/platforms/android/java/org/nativescript/widgets/FileHelper.java +815 -0
  20. package/platforms/android/java/org/nativescript/widgets/FlexLine.java +177 -0
  21. package/platforms/android/java/org/nativescript/widgets/FlexboxLayout.java +2769 -0
  22. package/platforms/android/java/org/nativescript/widgets/FragmentBase.java +14 -0
  23. package/platforms/android/java/org/nativescript/widgets/GridLayout.java +1172 -0
  24. package/platforms/android/java/org/nativescript/widgets/GridUnitType.java +10 -0
  25. package/platforms/android/java/org/nativescript/widgets/HorizontalScrollView.java +256 -0
  26. package/platforms/android/java/org/nativescript/widgets/ImageView.java +423 -0
  27. package/platforms/android/java/org/nativescript/widgets/ItemSpec.java +56 -0
  28. package/platforms/android/java/org/nativescript/widgets/LayoutBase.java +98 -0
  29. package/platforms/android/java/org/nativescript/widgets/LinearGradientDefinition.java +46 -0
  30. package/platforms/android/java/org/nativescript/widgets/Orientation.java +9 -0
  31. package/platforms/android/java/org/nativescript/widgets/OriginPoint.java +74 -0
  32. package/platforms/android/java/org/nativescript/widgets/ScrollSavedState.java +63 -0
  33. package/platforms/android/java/org/nativescript/widgets/SegmentedBarColorDrawable.java +27 -0
  34. package/platforms/android/java/org/nativescript/widgets/StackLayout.java +231 -0
  35. package/platforms/android/java/org/nativescript/widgets/StyleableTextView.java +50 -0
  36. package/platforms/android/java/org/nativescript/widgets/TabIconRenderingMode.java +6 -0
  37. package/platforms/android/java/org/nativescript/widgets/TabItemSpec.java +15 -0
  38. package/platforms/android/java/org/nativescript/widgets/TabLayout.java +451 -0
  39. package/platforms/android/java/org/nativescript/widgets/TabStrip.java +294 -0
  40. package/platforms/android/java/org/nativescript/widgets/TabViewPager.java +64 -0
  41. package/platforms/android/java/org/nativescript/widgets/TabsBar.java +443 -0
  42. package/platforms/android/java/org/nativescript/widgets/Utils.java +546 -0
  43. package/platforms/android/java/org/nativescript/widgets/VerticalScrollView.java +258 -0
  44. package/platforms/android/java/org/nativescript/widgets/ViewHelper.java +564 -0
  45. package/platforms/android/java/org/nativescript/widgets/WrapLayout.java +252 -0
  46. package/platforms/android/java/org/nativescript/widgets/image/AsyncTask.java +679 -0
  47. package/platforms/android/java/org/nativescript/widgets/image/BitmapOwner.java +17 -0
  48. package/platforms/android/java/org/nativescript/widgets/image/Cache.java +471 -0
  49. package/platforms/android/java/org/nativescript/widgets/image/DiskLruCache.java +970 -0
  50. package/platforms/android/java/org/nativescript/widgets/image/Fetcher.java +747 -0
  51. package/platforms/android/java/org/nativescript/widgets/image/Utils.java +58 -0
  52. package/platforms/android/java/org/nativescript/widgets/image/Worker.java +571 -0
  53. package/platforms/ios/src/TNSWidgets/Info.plist +26 -0
  54. package/platforms/ios/src/TNSWidgets/NSData+Async.m +42 -0
  55. package/platforms/ios/src/TNSWidgets/NSFileHandle+Async.m +82 -0
  56. package/platforms/ios/src/TNSWidgets/NSObject+Swizzling.m +68 -0
  57. package/platforms/ios/src/TNSWidgets/NSString+Async.m +51 -0
  58. package/platforms/ios/src/TNSWidgets/TNSLabel.m +42 -0
  59. package/platforms/ios/src/TNSWidgets/UIImage+TNSBlocks.m +77 -0
  60. package/platforms/ios/src/TNSWidgets/UIView+PassThroughParent.m +53 -0
  61. package/platforms/ios/src/TNSWidgets/UIView+PropertyBag.m +72 -0
  62. package/platforms/ios/src/module.modulemap +5 -0
  63. package/platforms/android/widgets-release.aar +0 -0
  64. package/platforms/ios/TNSWidgets.xcframework/Info.plist +0 -102
  65. package/platforms/ios/TNSWidgets.xcframework/ios-arm64/TNSWidgets.framework/Headers/NSCCrypto.h +0 -60
  66. package/platforms/ios/TNSWidgets.xcframework/ios-arm64/TNSWidgets.framework/Headers/TNSProcess.h +0 -29
  67. package/platforms/ios/TNSWidgets.xcframework/ios-arm64/TNSWidgets.framework/Info.plist +0 -0
  68. package/platforms/ios/TNSWidgets.xcframework/ios-arm64/TNSWidgets.framework/Modules/module.modulemap +0 -6
  69. package/platforms/ios/TNSWidgets.xcframework/ios-arm64/TNSWidgets.framework/TNSWidgets +0 -0
  70. package/platforms/ios/TNSWidgets.xcframework/ios-arm64/dSYMs/TNSWidgets.framework.dSYM/Contents/Info.plist +0 -20
  71. package/platforms/ios/TNSWidgets.xcframework/ios-arm64/dSYMs/TNSWidgets.framework.dSYM/Contents/Resources/DWARF/TNSWidgets +0 -0
  72. package/platforms/ios/TNSWidgets.xcframework/ios-arm64/dSYMs/TNSWidgets.framework.dSYM/Contents/Resources/Relocations/aarch64/TNSWidgets.yml +0 -82
  73. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-maccatalyst/TNSWidgets.framework/Headers/NSCCrypto.h +0 -60
  74. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-maccatalyst/TNSWidgets.framework/Headers/NSData+Async.h +0 -24
  75. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-maccatalyst/TNSWidgets.framework/Headers/NSFileHandle+Async.h +0 -22
  76. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-maccatalyst/TNSWidgets.framework/Headers/NSString+Async.h +0 -25
  77. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-maccatalyst/TNSWidgets.framework/Headers/TNSLabel.h +0 -16
  78. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-maccatalyst/TNSWidgets.framework/Headers/TNSProcess.h +0 -29
  79. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-maccatalyst/TNSWidgets.framework/Headers/TNSWidgets.h +0 -25
  80. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-maccatalyst/TNSWidgets.framework/Headers/UIImage+TNSBlocks.h +0 -26
  81. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-maccatalyst/TNSWidgets.framework/Headers/UIView+PassThroughParent.h +0 -17
  82. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-maccatalyst/TNSWidgets.framework/Modules/module.modulemap +0 -6
  83. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-maccatalyst/TNSWidgets.framework/PrivateHeaders/NSObject+Swizzling.h +0 -17
  84. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-maccatalyst/TNSWidgets.framework/PrivateHeaders/UIView+PropertyBag.h +0 -18
  85. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-maccatalyst/TNSWidgets.framework/Resources/Info.plist +0 -52
  86. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-maccatalyst/TNSWidgets.framework/Versions/A/Headers/NSCCrypto.h +0 -60
  87. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-maccatalyst/TNSWidgets.framework/Versions/A/Headers/NSData+Async.h +0 -24
  88. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-maccatalyst/TNSWidgets.framework/Versions/A/Headers/NSFileHandle+Async.h +0 -22
  89. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-maccatalyst/TNSWidgets.framework/Versions/A/Headers/NSString+Async.h +0 -25
  90. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-maccatalyst/TNSWidgets.framework/Versions/A/Headers/TNSLabel.h +0 -16
  91. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-maccatalyst/TNSWidgets.framework/Versions/A/Headers/TNSProcess.h +0 -29
  92. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-maccatalyst/TNSWidgets.framework/Versions/A/Headers/TNSWidgets.h +0 -25
  93. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-maccatalyst/TNSWidgets.framework/Versions/A/Headers/UIImage+TNSBlocks.h +0 -26
  94. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-maccatalyst/TNSWidgets.framework/Versions/A/Headers/UIView+PassThroughParent.h +0 -17
  95. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-maccatalyst/TNSWidgets.framework/Versions/A/Modules/module.modulemap +0 -6
  96. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-maccatalyst/TNSWidgets.framework/Versions/A/PrivateHeaders/NSObject+Swizzling.h +0 -17
  97. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-maccatalyst/TNSWidgets.framework/Versions/A/PrivateHeaders/UIView+PropertyBag.h +0 -18
  98. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-maccatalyst/TNSWidgets.framework/Versions/A/Resources/Info.plist +0 -52
  99. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-maccatalyst/TNSWidgets.framework/Versions/A/TNSWidgets +0 -0
  100. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-maccatalyst/TNSWidgets.framework/Versions/Current/Headers/NSCCrypto.h +0 -60
  101. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-maccatalyst/TNSWidgets.framework/Versions/Current/Headers/NSData+Async.h +0 -24
  102. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-maccatalyst/TNSWidgets.framework/Versions/Current/Headers/NSFileHandle+Async.h +0 -22
  103. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-maccatalyst/TNSWidgets.framework/Versions/Current/Headers/NSString+Async.h +0 -25
  104. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-maccatalyst/TNSWidgets.framework/Versions/Current/Headers/TNSLabel.h +0 -16
  105. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-maccatalyst/TNSWidgets.framework/Versions/Current/Headers/TNSProcess.h +0 -29
  106. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-maccatalyst/TNSWidgets.framework/Versions/Current/Headers/TNSWidgets.h +0 -25
  107. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-maccatalyst/TNSWidgets.framework/Versions/Current/Headers/UIImage+TNSBlocks.h +0 -26
  108. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-maccatalyst/TNSWidgets.framework/Versions/Current/Headers/UIView+PassThroughParent.h +0 -17
  109. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-maccatalyst/TNSWidgets.framework/Versions/Current/Modules/module.modulemap +0 -6
  110. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-maccatalyst/TNSWidgets.framework/Versions/Current/PrivateHeaders/NSObject+Swizzling.h +0 -17
  111. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-maccatalyst/TNSWidgets.framework/Versions/Current/PrivateHeaders/UIView+PropertyBag.h +0 -18
  112. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-maccatalyst/TNSWidgets.framework/Versions/Current/Resources/Info.plist +0 -52
  113. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-maccatalyst/TNSWidgets.framework/Versions/Current/TNSWidgets +0 -0
  114. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-maccatalyst/dSYMs/TNSWidgets.framework.dSYM/Contents/Info.plist +0 -20
  115. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-maccatalyst/dSYMs/TNSWidgets.framework.dSYM/Contents/Resources/DWARF/TNSWidgets +0 -0
  116. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-maccatalyst/dSYMs/TNSWidgets.framework.dSYM/Contents/Resources/Relocations/aarch64/TNSWidgets.yml +0 -82
  117. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-maccatalyst/dSYMs/TNSWidgets.framework.dSYM/Contents/Resources/Relocations/x86_64/TNSWidgets.yml +0 -82
  118. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-simulator/TNSWidgets.framework/Headers/NSCCrypto.h +0 -60
  119. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-simulator/TNSWidgets.framework/Headers/NSData+Async.h +0 -24
  120. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-simulator/TNSWidgets.framework/Headers/NSFileHandle+Async.h +0 -22
  121. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-simulator/TNSWidgets.framework/Headers/NSString+Async.h +0 -25
  122. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-simulator/TNSWidgets.framework/Headers/TNSLabel.h +0 -16
  123. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-simulator/TNSWidgets.framework/Headers/TNSProcess.h +0 -29
  124. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-simulator/TNSWidgets.framework/Headers/TNSWidgets.h +0 -25
  125. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-simulator/TNSWidgets.framework/Headers/UIImage+TNSBlocks.h +0 -26
  126. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-simulator/TNSWidgets.framework/Headers/UIView+PassThroughParent.h +0 -17
  127. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-simulator/TNSWidgets.framework/Info.plist +0 -0
  128. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-simulator/TNSWidgets.framework/Modules/module.modulemap +0 -6
  129. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-simulator/TNSWidgets.framework/PrivateHeaders/NSObject+Swizzling.h +0 -17
  130. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-simulator/TNSWidgets.framework/PrivateHeaders/UIView+PropertyBag.h +0 -18
  131. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-simulator/TNSWidgets.framework/TNSWidgets +0 -0
  132. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-simulator/TNSWidgets.framework/_CodeSignature/CodeResources +0 -223
  133. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-simulator/dSYMs/TNSWidgets.framework.dSYM/Contents/Info.plist +0 -20
  134. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-simulator/dSYMs/TNSWidgets.framework.dSYM/Contents/Resources/DWARF/TNSWidgets +0 -0
  135. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-simulator/dSYMs/TNSWidgets.framework.dSYM/Contents/Resources/Relocations/aarch64/TNSWidgets.yml +0 -82
  136. package/platforms/ios/TNSWidgets.xcframework/ios-arm64_x86_64-simulator/dSYMs/TNSWidgets.framework.dSYM/Contents/Resources/Relocations/x86_64/TNSWidgets.yml +0 -82
  137. package/platforms/ios/TNSWidgets.xcframework/xros-arm64/TNSWidgets.framework/Headers/NSCCrypto.h +0 -60
  138. package/platforms/ios/TNSWidgets.xcframework/xros-arm64/TNSWidgets.framework/Headers/NSData+Async.h +0 -24
  139. package/platforms/ios/TNSWidgets.xcframework/xros-arm64/TNSWidgets.framework/Headers/NSFileHandle+Async.h +0 -22
  140. package/platforms/ios/TNSWidgets.xcframework/xros-arm64/TNSWidgets.framework/Headers/NSString+Async.h +0 -25
  141. package/platforms/ios/TNSWidgets.xcframework/xros-arm64/TNSWidgets.framework/Headers/TNSLabel.h +0 -16
  142. package/platforms/ios/TNSWidgets.xcframework/xros-arm64/TNSWidgets.framework/Headers/TNSProcess.h +0 -29
  143. package/platforms/ios/TNSWidgets.xcframework/xros-arm64/TNSWidgets.framework/Headers/TNSWidgets.h +0 -25
  144. package/platforms/ios/TNSWidgets.xcframework/xros-arm64/TNSWidgets.framework/Headers/UIImage+TNSBlocks.h +0 -26
  145. package/platforms/ios/TNSWidgets.xcframework/xros-arm64/TNSWidgets.framework/Headers/UIView+PassThroughParent.h +0 -17
  146. package/platforms/ios/TNSWidgets.xcframework/xros-arm64/TNSWidgets.framework/Info.plist +0 -0
  147. package/platforms/ios/TNSWidgets.xcframework/xros-arm64/TNSWidgets.framework/Modules/module.modulemap +0 -6
  148. package/platforms/ios/TNSWidgets.xcframework/xros-arm64/TNSWidgets.framework/PrivateHeaders/NSObject+Swizzling.h +0 -17
  149. package/platforms/ios/TNSWidgets.xcframework/xros-arm64/TNSWidgets.framework/PrivateHeaders/UIView+PropertyBag.h +0 -18
  150. package/platforms/ios/TNSWidgets.xcframework/xros-arm64/TNSWidgets.framework/TNSWidgets +0 -0
  151. package/platforms/ios/TNSWidgets.xcframework/xros-arm64/dSYMs/TNSWidgets.framework.dSYM/Contents/Info.plist +0 -20
  152. package/platforms/ios/TNSWidgets.xcframework/xros-arm64/dSYMs/TNSWidgets.framework.dSYM/Contents/Resources/DWARF/TNSWidgets +0 -0
  153. package/platforms/ios/TNSWidgets.xcframework/xros-arm64/dSYMs/TNSWidgets.framework.dSYM/Contents/Resources/Relocations/aarch64/TNSWidgets.yml +0 -82
  154. package/platforms/ios/TNSWidgets.xcframework/xros-arm64_x86_64-simulator/TNSWidgets.framework/Headers/NSCCrypto.h +0 -60
  155. package/platforms/ios/TNSWidgets.xcframework/xros-arm64_x86_64-simulator/TNSWidgets.framework/Headers/NSData+Async.h +0 -24
  156. package/platforms/ios/TNSWidgets.xcframework/xros-arm64_x86_64-simulator/TNSWidgets.framework/Headers/NSFileHandle+Async.h +0 -22
  157. package/platforms/ios/TNSWidgets.xcframework/xros-arm64_x86_64-simulator/TNSWidgets.framework/Headers/NSString+Async.h +0 -25
  158. package/platforms/ios/TNSWidgets.xcframework/xros-arm64_x86_64-simulator/TNSWidgets.framework/Headers/TNSLabel.h +0 -16
  159. package/platforms/ios/TNSWidgets.xcframework/xros-arm64_x86_64-simulator/TNSWidgets.framework/Headers/TNSProcess.h +0 -29
  160. package/platforms/ios/TNSWidgets.xcframework/xros-arm64_x86_64-simulator/TNSWidgets.framework/Headers/TNSWidgets.h +0 -25
  161. package/platforms/ios/TNSWidgets.xcframework/xros-arm64_x86_64-simulator/TNSWidgets.framework/Headers/UIImage+TNSBlocks.h +0 -26
  162. package/platforms/ios/TNSWidgets.xcframework/xros-arm64_x86_64-simulator/TNSWidgets.framework/Headers/UIView+PassThroughParent.h +0 -17
  163. package/platforms/ios/TNSWidgets.xcframework/xros-arm64_x86_64-simulator/TNSWidgets.framework/Info.plist +0 -0
  164. package/platforms/ios/TNSWidgets.xcframework/xros-arm64_x86_64-simulator/TNSWidgets.framework/Modules/module.modulemap +0 -6
  165. package/platforms/ios/TNSWidgets.xcframework/xros-arm64_x86_64-simulator/TNSWidgets.framework/PrivateHeaders/NSObject+Swizzling.h +0 -17
  166. package/platforms/ios/TNSWidgets.xcframework/xros-arm64_x86_64-simulator/TNSWidgets.framework/PrivateHeaders/UIView+PropertyBag.h +0 -18
  167. package/platforms/ios/TNSWidgets.xcframework/xros-arm64_x86_64-simulator/TNSWidgets.framework/TNSWidgets +0 -0
  168. package/platforms/ios/TNSWidgets.xcframework/xros-arm64_x86_64-simulator/TNSWidgets.framework/_CodeSignature/CodeResources +0 -223
  169. package/platforms/ios/TNSWidgets.xcframework/xros-arm64_x86_64-simulator/dSYMs/TNSWidgets.framework.dSYM/Contents/Info.plist +0 -20
  170. package/platforms/ios/TNSWidgets.xcframework/xros-arm64_x86_64-simulator/dSYMs/TNSWidgets.framework.dSYM/Contents/Resources/DWARF/TNSWidgets +0 -0
  171. package/platforms/ios/TNSWidgets.xcframework/xros-arm64_x86_64-simulator/dSYMs/TNSWidgets.framework.dSYM/Contents/Resources/Relocations/aarch64/TNSWidgets.yml +0 -82
  172. package/platforms/ios/TNSWidgets.xcframework/xros-arm64_x86_64-simulator/dSYMs/TNSWidgets.framework.dSYM/Contents/Resources/Relocations/x86_64/TNSWidgets.yml +0 -82
  173. /package/platforms/ios/{TNSWidgets.xcframework/ios-arm64/TNSWidgets.framework/Headers → src/TNSWidgets}/NSData+Async.h +0 -0
  174. /package/platforms/ios/{TNSWidgets.xcframework/ios-arm64/TNSWidgets.framework/Headers → src/TNSWidgets}/NSFileHandle+Async.h +0 -0
  175. /package/platforms/ios/{TNSWidgets.xcframework/ios-arm64/TNSWidgets.framework/PrivateHeaders → src/TNSWidgets}/NSObject+Swizzling.h +0 -0
  176. /package/platforms/ios/{TNSWidgets.xcframework/ios-arm64/TNSWidgets.framework/Headers → src/TNSWidgets}/NSString+Async.h +0 -0
  177. /package/platforms/ios/{TNSWidgets.xcframework/ios-arm64/TNSWidgets.framework/Headers → src/TNSWidgets}/TNSLabel.h +0 -0
  178. /package/platforms/ios/{TNSWidgets.xcframework/ios-arm64/TNSWidgets.framework/Headers → src/TNSWidgets}/TNSWidgets.h +0 -0
  179. /package/platforms/ios/{TNSWidgets.xcframework/ios-arm64/TNSWidgets.framework/Headers → src/TNSWidgets}/UIImage+TNSBlocks.h +0 -0
  180. /package/platforms/ios/{TNSWidgets.xcframework/ios-arm64/TNSWidgets.framework/Headers → src/TNSWidgets}/UIView+PassThroughParent.h +0 -0
  181. /package/platforms/ios/{TNSWidgets.xcframework/ios-arm64/TNSWidgets.framework/PrivateHeaders → src/TNSWidgets}/UIView+PropertyBag.h +0 -0
@@ -0,0 +1,2769 @@
1
+ /*
2
+ * Copyright 2016 Google Inc. All rights reserved.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ package org.nativescript.widgets;
18
+
19
+ import android.content.Context;
20
+ import android.graphics.Canvas;
21
+ import android.graphics.drawable.Drawable;
22
+ import android.util.AttributeSet;
23
+ import android.util.SparseIntArray;
24
+ import android.view.View;
25
+ import android.view.ViewGroup;
26
+ import android.widget.FrameLayout;
27
+ import android.widget.LinearLayout;
28
+ import android.widget.RelativeLayout;
29
+
30
+ import androidx.annotation.IntDef;
31
+ import androidx.annotation.NonNull;
32
+ import androidx.core.view.ViewCompat;
33
+
34
+ import java.lang.annotation.Retention;
35
+ import java.lang.annotation.RetentionPolicy;
36
+ import java.util.ArrayList;
37
+ import java.util.Arrays;
38
+ import java.util.Collections;
39
+ import java.util.List;
40
+
41
+ /**
42
+ * A layout that arranges its children in a way its attributes can be specified like the
43
+ * CSS Flexible Box Layout Module.
44
+ * This class extends the {@link ViewGroup} like other layout classes such as {@link LinearLayout}
45
+ * or {@link RelativeLayout}, the attributes can be specified from a layout XML or from code.
46
+ * <p>
47
+ * The supported attributes that you can use are:
48
+ * <ul>
49
+ * <li>{@code flexDirection}</li>
50
+ * <li>{@code flexWrap}</li>
51
+ * <li>{@code justifyContent}</li>
52
+ * <li>{@code alignItems}</li>
53
+ * <li>{@code alignContent}</li>
54
+ * <li>{@code showDivider}</li>
55
+ * <li>{@code showDividerHorizontal}</li>
56
+ * <li>{@code showDividerVertical}</li>
57
+ * <li>{@code dividerDrawable}</li>
58
+ * <li>{@code dividerDrawableHorizontal}</li>
59
+ * <li>{@code dividerDrawableVertical}</li>
60
+ * </ul>
61
+ * for the FlexboxLayout.
62
+ * <p>
63
+ * And for the children of the FlexboxLayout, you can use:
64
+ * <ul>
65
+ * <li>{@code layout_order}</li>
66
+ * <li>{@code layout_flexGrow}</li>
67
+ * <li>{@code layout_flexShrink}</li>
68
+ * <li>{@code layout_flexBasisPercent}</li>
69
+ * <li>{@code layout_alignSelf}</li>
70
+ * <li>{@code layout_minWidth}</li>
71
+ * <li>{@code layout_minHeight}</li>
72
+ * <li>{@code layout_maxWidth}</li>
73
+ * <li>{@code layout_maxHeight}</li>
74
+ * <li>{@code layout_wrapBefore}</li>
75
+ * </ul>
76
+ */
77
+ public class FlexboxLayout extends LayoutBase {
78
+
79
+ @IntDef({FLEX_DIRECTION_ROW, FLEX_DIRECTION_ROW_REVERSE, FLEX_DIRECTION_COLUMN,
80
+ FLEX_DIRECTION_COLUMN_REVERSE})
81
+ @Retention(RetentionPolicy.SOURCE)
82
+ public @interface FlexDirection {
83
+
84
+ }
85
+
86
+ public static final int FLEX_DIRECTION_ROW = 0;
87
+
88
+ public static final int FLEX_DIRECTION_ROW_REVERSE = 1;
89
+
90
+ public static final int FLEX_DIRECTION_COLUMN = 2;
91
+
92
+ public static final int FLEX_DIRECTION_COLUMN_REVERSE = 3;
93
+
94
+ /**
95
+ * The direction children items are placed inside the Flexbox layout, it determines the
96
+ * direction of the main axis (and the cross axis, perpendicular to the main axis).
97
+ * <ul>
98
+ * <li>
99
+ * {@link #FLEX_DIRECTION_ROW}: Main axis direction -> horizontal. Main start to
100
+ * main end -> Left to right (in LTR languages).
101
+ * Cross start to cross end -> Top to bottom
102
+ * </li>
103
+ * <li>
104
+ * {@link #FLEX_DIRECTION_ROW_REVERSE}: Main axis direction -> horizontal. Main start
105
+ * to main end -> Right to left (in LTR languages). Cross start to cross end ->
106
+ * Top to bottom.
107
+ * </li>
108
+ * <li>
109
+ * {@link #FLEX_DIRECTION_COLUMN}: Main axis direction -> vertical. Main start
110
+ * to main end -> Top to bottom. Cross start to cross end ->
111
+ * Left to right (In LTR languages).
112
+ * </li>
113
+ * <li>
114
+ * {@link #FLEX_DIRECTION_COLUMN_REVERSE}: Main axis direction -> vertical. Main start
115
+ * to main end -> Bottom to top. Cross start to cross end -> Left to right
116
+ * (In LTR languages)
117
+ * </li>
118
+ * </ul>
119
+ * The default value is {@link #FLEX_DIRECTION_ROW}.
120
+ */
121
+ private int mFlexDirection = FLEX_DIRECTION_ROW;
122
+
123
+
124
+ @IntDef({FLEX_WRAP_NOWRAP, FLEX_WRAP_WRAP, FLEX_WRAP_WRAP_REVERSE})
125
+ @Retention(RetentionPolicy.SOURCE)
126
+ public @interface FlexWrap {
127
+
128
+ }
129
+
130
+ public static final int FLEX_WRAP_NOWRAP = 0;
131
+
132
+ public static final int FLEX_WRAP_WRAP = 1;
133
+
134
+ public static final int FLEX_WRAP_WRAP_REVERSE = 2;
135
+
136
+ /**
137
+ * This attribute controls whether the flex container is single-line or multi-line, and the
138
+ * direction of the cross axis.
139
+ * <ul>
140
+ * <li>{@link #FLEX_WRAP_NOWRAP}: The flex container is single-line.</li>
141
+ * <li>{@link #FLEX_WRAP_WRAP}: The flex container is multi-line.</li>
142
+ * <li>{@link #FLEX_WRAP_WRAP_REVERSE}: The flex container is multi-line. The direction of the
143
+ * cross axis is opposed to the direction as the {@link #FLEX_WRAP_WRAP}</li>
144
+ * </ul>
145
+ * The default value is {@link #FLEX_WRAP_NOWRAP}.
146
+ */
147
+ private int mFlexWrap = FLEX_WRAP_NOWRAP;
148
+
149
+
150
+ @IntDef({JUSTIFY_CONTENT_FLEX_START, JUSTIFY_CONTENT_FLEX_END, JUSTIFY_CONTENT_CENTER,
151
+ JUSTIFY_CONTENT_SPACE_BETWEEN, JUSTIFY_CONTENT_SPACE_AROUND})
152
+ @Retention(RetentionPolicy.SOURCE)
153
+ public @interface JustifyContent {
154
+
155
+ }
156
+
157
+ public static final int JUSTIFY_CONTENT_FLEX_START = 0;
158
+
159
+ public static final int JUSTIFY_CONTENT_FLEX_END = 1;
160
+
161
+ public static final int JUSTIFY_CONTENT_CENTER = 2;
162
+
163
+ public static final int JUSTIFY_CONTENT_SPACE_BETWEEN = 3;
164
+
165
+ public static final int JUSTIFY_CONTENT_SPACE_AROUND = 4;
166
+
167
+ /**
168
+ * This attribute controls the alignment along the main axis.
169
+ * The default value is {@link #JUSTIFY_CONTENT_FLEX_START}.
170
+ */
171
+ private int mJustifyContent = JUSTIFY_CONTENT_FLEX_START;
172
+
173
+
174
+ @IntDef({ALIGN_ITEMS_FLEX_START, ALIGN_ITEMS_FLEX_END, ALIGN_ITEMS_CENTER,
175
+ ALIGN_ITEMS_BASELINE, ALIGN_ITEMS_STRETCH})
176
+ @Retention(RetentionPolicy.SOURCE)
177
+ public @interface AlignItems {
178
+
179
+ }
180
+
181
+ public static final int ALIGN_ITEMS_FLEX_START = 0;
182
+
183
+ public static final int ALIGN_ITEMS_FLEX_END = 1;
184
+
185
+ public static final int ALIGN_ITEMS_CENTER = 2;
186
+
187
+ public static final int ALIGN_ITEMS_BASELINE = 3;
188
+
189
+ public static final int ALIGN_ITEMS_STRETCH = 4;
190
+
191
+ /**
192
+ * This attribute controls the alignment along the cross axis.
193
+ * The default value is {@link #ALIGN_ITEMS_STRETCH}.
194
+ */
195
+ private int mAlignItems = ALIGN_ITEMS_STRETCH;
196
+
197
+
198
+ @IntDef({ALIGN_CONTENT_FLEX_START, ALIGN_CONTENT_FLEX_END, ALIGN_CONTENT_CENTER,
199
+ ALIGN_CONTENT_SPACE_BETWEEN, ALIGN_CONTENT_SPACE_AROUND, ALIGN_CONTENT_STRETCH})
200
+ @Retention(RetentionPolicy.SOURCE)
201
+ public @interface AlignContent {
202
+
203
+ }
204
+
205
+ public static final int ALIGN_CONTENT_FLEX_START = 0;
206
+
207
+ public static final int ALIGN_CONTENT_FLEX_END = 1;
208
+
209
+ public static final int ALIGN_CONTENT_CENTER = 2;
210
+
211
+ public static final int ALIGN_CONTENT_SPACE_BETWEEN = 3;
212
+
213
+ public static final int ALIGN_CONTENT_SPACE_AROUND = 4;
214
+
215
+ public static final int ALIGN_CONTENT_STRETCH = 5;
216
+
217
+ /**
218
+ * This attribute controls the alignment of the flex lines in the flex container.
219
+ * The default value is {@link #ALIGN_CONTENT_STRETCH}.
220
+ */
221
+ private int mAlignContent = ALIGN_CONTENT_STRETCH;
222
+
223
+ /**
224
+ * The int definition to be used as the arguments for the {@link #setShowDivider(int)},
225
+ * {@link #setShowDividerHorizontal(int)} or {@link #setShowDividerVertical(int)}.
226
+ * One or more of the values (such as
227
+ * {@link #SHOW_DIVIDER_BEGINNING} | {@link #SHOW_DIVIDER_MIDDLE}) can be passed to those set
228
+ * methods.
229
+ */
230
+ @IntDef(flag = true,
231
+ value = {
232
+ SHOW_DIVIDER_NONE,
233
+ SHOW_DIVIDER_BEGINNING,
234
+ SHOW_DIVIDER_MIDDLE,
235
+ SHOW_DIVIDER_END
236
+ })
237
+ @Retention(RetentionPolicy.SOURCE)
238
+ public @interface DividerMode {
239
+
240
+ }
241
+
242
+ /**
243
+ * Constant to how no dividers
244
+ */
245
+ public static final int SHOW_DIVIDER_NONE = 0;
246
+
247
+ /**
248
+ * Constant to show a divider at the beginning of the flex lines (or flex items).
249
+ */
250
+ public static final int SHOW_DIVIDER_BEGINNING = 1;
251
+
252
+ /**
253
+ * Constant to show dividers between flex lines or flex items.
254
+ */
255
+ public static final int SHOW_DIVIDER_MIDDLE = 1 << 1;
256
+
257
+ /**
258
+ * Constant to show a divider at the end of the flex lines or flex items.
259
+ */
260
+ public static final int SHOW_DIVIDER_END = 1 << 2;
261
+
262
+ /**
263
+ * The drawable to be drawn for the horizontal dividers.
264
+ */
265
+ private Drawable mDividerDrawableHorizontal;
266
+
267
+ /**
268
+ * The drawable to be drawn for the vertical dividers.
269
+ */
270
+ private Drawable mDividerDrawableVertical;
271
+
272
+ /**
273
+ * Indicates the divider mode for the {@link #mDividerDrawableHorizontal}. The value needs to
274
+ * be the combination of the value of {@link #SHOW_DIVIDER_NONE},
275
+ * {@link #SHOW_DIVIDER_BEGINNING}, {@link #SHOW_DIVIDER_MIDDLE} and {@link #SHOW_DIVIDER_END}
276
+ */
277
+ private int mShowDividerHorizontal;
278
+
279
+ /**
280
+ * Indicates the divider mode for the {@link #mDividerDrawableVertical}. The value needs to
281
+ * be the combination of the value of {@link #SHOW_DIVIDER_NONE},
282
+ * {@link #SHOW_DIVIDER_BEGINNING}, {@link #SHOW_DIVIDER_MIDDLE} and {@link #SHOW_DIVIDER_END}
283
+ */
284
+ private int mShowDividerVertical;
285
+
286
+ /**
287
+ * The height of the {@link #mDividerDrawableHorizontal}.
288
+ */
289
+ private int mDividerHorizontalHeight;
290
+
291
+ /**
292
+ * The width of the {@link #mDividerDrawableVertical}.
293
+ */
294
+ private int mDividerVerticalWidth;
295
+
296
+ /**
297
+ * Holds reordered indices, which {@link LayoutParams#order} parameters are taken into account
298
+ */
299
+ private int[] mReorderedIndices;
300
+
301
+ /**
302
+ * Caches the {@link LayoutParams#order} attributes for children views.
303
+ * Key: the index of the view ({@link #mReorderedIndices} isn't taken into account)
304
+ * Value: the value for the order attribute
305
+ */
306
+ private SparseIntArray mOrderCache;
307
+
308
+ private List<FlexLine> mFlexLines = new ArrayList<>();
309
+
310
+ /**
311
+ * Holds the 'frozen' state of children during measure. If a view is frozen it will no longer
312
+ * expand or shrink regardless of flexGrow/flexShrink. Items are indexed by the child's
313
+ * reordered index.
314
+ */
315
+ private boolean[] mChildrenFrozen;
316
+
317
+ public FlexboxLayout(Context context) {
318
+ this(context, null);
319
+ }
320
+
321
+ public FlexboxLayout(Context context, AttributeSet attrs) {
322
+ this(context, attrs, 0);
323
+ }
324
+
325
+ public FlexboxLayout(Context context, AttributeSet attrs, int defStyleAttr) {
326
+ super(context, attrs, defStyleAttr);
327
+
328
+ // NOTE: We do not support android xml.
329
+ // TypedArray a = context.obtainStyledAttributes(
330
+ // attrs, R.styleable.FlexboxLayout, defStyleAttr, 0);
331
+ // mFlexDirection = a.getInt(R.styleable.FlexboxLayout_flexDirection, FLEX_DIRECTION_ROW);
332
+ // mFlexWrap = a.getInt(R.styleable.FlexboxLayout_flexWrap, FLEX_WRAP_NOWRAP);
333
+ // mJustifyContent = a
334
+ // .getInt(R.styleable.FlexboxLayout_justifyContent, JUSTIFY_CONTENT_FLEX_START);
335
+ // mAlignItems = a.getInt(R.styleable.FlexboxLayout_alignItems, ALIGN_ITEMS_STRETCH);
336
+ // mAlignContent = a.getInt(R.styleable.FlexboxLayout_alignContent, ALIGN_CONTENT_STRETCH);
337
+ // Drawable drawable = a.getDrawable(R.styleable.FlexboxLayout_dividerDrawable);
338
+ // if (drawable != null) {
339
+ // setDividerDrawableHorizontal(drawable);
340
+ // setDividerDrawableVertical(drawable);
341
+ // }
342
+ // Drawable drawableHorizontal = a
343
+ // .getDrawable(R.styleable.FlexboxLayout_dividerDrawableHorizontal);
344
+ // if (drawableHorizontal != null) {
345
+ // setDividerDrawableHorizontal(drawableHorizontal);
346
+ // }
347
+ // Drawable drawableVertical = a
348
+ // .getDrawable(R.styleable.FlexboxLayout_dividerDrawableVertical);
349
+ // if (drawableVertical != null) {
350
+ // setDividerDrawableVertical(drawableVertical);
351
+ // }
352
+ // int dividerMode = a.getInt(R.styleable.FlexboxLayout_showDivider, SHOW_DIVIDER_NONE);
353
+ // if (dividerMode != SHOW_DIVIDER_NONE) {
354
+ // mShowDividerVertical = dividerMode;
355
+ // mShowDividerHorizontal = dividerMode;
356
+ // }
357
+ // int dividerModeVertical = a
358
+ // .getInt(R.styleable.FlexboxLayout_showDividerVertical, SHOW_DIVIDER_NONE);
359
+ // if (dividerModeVertical != SHOW_DIVIDER_NONE) {
360
+ // mShowDividerVertical = dividerModeVertical;
361
+ // }
362
+ // int dividerModeHorizontal = a
363
+ // .getInt(R.styleable.FlexboxLayout_showDividerHorizontal, SHOW_DIVIDER_NONE);
364
+ // if (dividerModeHorizontal != SHOW_DIVIDER_NONE) {
365
+ // mShowDividerHorizontal = dividerModeHorizontal;
366
+ // }
367
+ // a.recycle();
368
+ }
369
+
370
+ @Override
371
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
372
+ CommonLayoutParams.adjustChildrenLayoutParams(this, widthMeasureSpec, heightMeasureSpec);
373
+
374
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
375
+ if (isOrderChangedFromLastMeasurement()) {
376
+ mReorderedIndices = createReorderedIndices();
377
+ }
378
+ if (mChildrenFrozen == null || mChildrenFrozen.length < getChildCount()) {
379
+ mChildrenFrozen = new boolean[getChildCount()];
380
+ }
381
+
382
+ // TODO: Only calculate the children views which are affected from the last measure.
383
+
384
+ switch (mFlexDirection) {
385
+ case FLEX_DIRECTION_ROW: // Intentional fall through
386
+ case FLEX_DIRECTION_ROW_REVERSE:
387
+ measureHorizontal(widthMeasureSpec, heightMeasureSpec);
388
+ break;
389
+ case FLEX_DIRECTION_COLUMN: // Intentional fall through
390
+ case FLEX_DIRECTION_COLUMN_REVERSE:
391
+ measureVertical(widthMeasureSpec, heightMeasureSpec);
392
+ break;
393
+ default:
394
+ throw new IllegalStateException(
395
+ "Invalid value for the flex direction is set: " + mFlexDirection);
396
+ }
397
+
398
+ Arrays.fill(mChildrenFrozen, false);
399
+ }
400
+
401
+ /**
402
+ * Returns a View, which is reordered by taking {@link LayoutParams#order} parameters
403
+ * into account.
404
+ *
405
+ * @param index the index of the view
406
+ * @return the reordered view, which {@link LayoutParams@order} is taken into account.
407
+ * If the index is negative or out of bounds of the number of contained views,
408
+ * returns {@code null}.
409
+ */
410
+ public View getReorderedChildAt(int index) {
411
+ if (index < 0 || index >= mReorderedIndices.length) {
412
+ return null;
413
+ }
414
+ return getChildAt(mReorderedIndices[index]);
415
+ }
416
+
417
+ @Override
418
+ public void addView(View child, int index, ViewGroup.LayoutParams params) {
419
+ // Create an array for the reordered indices before the View is added in the parent
420
+ // ViewGroup since otherwise reordered indices won't be in effect before the
421
+ // FlexboxLayout's onMeasure is called.
422
+ // Because requestLayout is requested in the super.addView method.
423
+ mReorderedIndices = createReorderedIndices(child, index, params);
424
+ super.addView(child, index, params);
425
+ }
426
+
427
+ /**
428
+ * Create an array, which indicates the reordered indices that {@link LayoutParams#order}
429
+ * attributes are taken into account. This method takes a View before that is added as the
430
+ * parent ViewGroup's children.
431
+ *
432
+ * @param viewBeforeAdded the View instance before added to the array of children
433
+ * Views of the parent ViewGroup
434
+ * @param indexForViewBeforeAdded the index for the View before added to the array of the
435
+ * parent ViewGroup
436
+ * @param paramsForViewBeforeAdded the layout parameters for the View before added to the array
437
+ * of the parent ViewGroup
438
+ * @return an array which have the reordered indices
439
+ */
440
+ private int[] createReorderedIndices(View viewBeforeAdded, int indexForViewBeforeAdded,
441
+ ViewGroup.LayoutParams paramsForViewBeforeAdded) {
442
+ int childCount = getChildCount();
443
+ List<Order> orders = createOrders(childCount);
444
+ Order orderForViewToBeAdded = new Order();
445
+ if (viewBeforeAdded != null
446
+ && paramsForViewBeforeAdded instanceof FlexboxLayout.LayoutParams) {
447
+ orderForViewToBeAdded.order = ((LayoutParams) paramsForViewBeforeAdded).order;
448
+ } else {
449
+ orderForViewToBeAdded.order = LayoutParams.ORDER_DEFAULT;
450
+ }
451
+
452
+ if (indexForViewBeforeAdded == -1 || indexForViewBeforeAdded == childCount) {
453
+ orderForViewToBeAdded.index = childCount;
454
+ } else if (indexForViewBeforeAdded < getChildCount()) {
455
+ orderForViewToBeAdded.index = indexForViewBeforeAdded;
456
+ for (int i = indexForViewBeforeAdded; i < childCount; i++) {
457
+ orders.get(i).index++;
458
+ }
459
+ } else {
460
+ // This path is not expected since OutOfBoundException will be thrown in the ViewGroup
461
+ // But setting the index for fail-safe
462
+ orderForViewToBeAdded.index = childCount;
463
+ }
464
+ orders.add(orderForViewToBeAdded);
465
+
466
+ return sortOrdersIntoReorderedIndices(childCount + 1, orders);
467
+ }
468
+
469
+ /**
470
+ * Create an array, which indicates the reordered indices that {@link LayoutParams#order}
471
+ * attributes are taken into account.
472
+ *
473
+ * @return @return an array which have the reordered indices
474
+ */
475
+ private int[] createReorderedIndices() {
476
+ int childCount = getChildCount();
477
+ List<Order> orders = createOrders(childCount);
478
+ return sortOrdersIntoReorderedIndices(childCount, orders);
479
+ }
480
+
481
+ private int[] sortOrdersIntoReorderedIndices(int childCount, List<Order> orders) {
482
+ Collections.sort(orders);
483
+ if (mOrderCache == null) {
484
+ mOrderCache = new SparseIntArray(childCount);
485
+ }
486
+ mOrderCache.clear();
487
+ int[] reorderedIndices = new int[childCount];
488
+ int i = 0;
489
+ for (Order order : orders) {
490
+ reorderedIndices[i] = order.index;
491
+ mOrderCache.append(i, order.order);
492
+ i++;
493
+ }
494
+ return reorderedIndices;
495
+ }
496
+
497
+ @NonNull
498
+ private List<Order> createOrders(int childCount) {
499
+ List<Order> orders = new ArrayList<>();
500
+ for (int i = 0; i < childCount; i++) {
501
+ View child = getChildAt(i);
502
+ LayoutParams params = (LayoutParams) child.getLayoutParams();
503
+ Order order = new Order();
504
+ order.order = params.order;
505
+ order.index = i;
506
+ orders.add(order);
507
+ }
508
+ return orders;
509
+ }
510
+
511
+ /**
512
+ * Returns if any of the children's {@link LayoutParams#order} attributes are changed
513
+ * from the last measurement.
514
+ *
515
+ * @return {@code true} if changed from the last measurement, {@code false} otherwise.
516
+ */
517
+ private boolean isOrderChangedFromLastMeasurement() {
518
+ int childCount = getChildCount();
519
+ if (mOrderCache == null) {
520
+ mOrderCache = new SparseIntArray(childCount);
521
+ }
522
+ if (mOrderCache.size() != childCount) {
523
+ return true;
524
+ }
525
+ for (int i = 0; i < childCount; i++) {
526
+ View view = getChildAt(i);
527
+ if (view == null) {
528
+ continue;
529
+ }
530
+ LayoutParams lp = (LayoutParams) view.getLayoutParams();
531
+ if (lp.order != mOrderCache.get(i)) {
532
+ return true;
533
+ }
534
+ }
535
+ return false;
536
+ }
537
+
538
+ /**
539
+ * Invalidates the cache of the orders so that they are recalculated.
540
+ */
541
+ public void invalidateOrdersCache() {
542
+ if (this.mOrderCache != null) {
543
+ this.mOrderCache.clear();
544
+ }
545
+ }
546
+
547
+ /**
548
+ * Sub method for {@link #onMeasure(int, int)}, when the main axis direction is horizontal
549
+ * (either left to right or right to left).
550
+ *
551
+ * @param widthMeasureSpec horizontal space requirements as imposed by the parent
552
+ * @param heightMeasureSpec vertical space requirements as imposed by the parent
553
+ * @see #onMeasure(int, int)
554
+ * @see #setFlexDirection(int)
555
+ * @see #setFlexWrap(int)
556
+ * @see #setAlignItems(int)
557
+ * @see #setAlignContent(int)
558
+ */
559
+ private void measureHorizontal(int widthMeasureSpec, int heightMeasureSpec) {
560
+ int widthMode = MeasureSpec.getMode(widthMeasureSpec);
561
+ int widthSize = MeasureSpec.getSize(widthMeasureSpec);
562
+ int childState = 0;
563
+
564
+ mFlexLines.clear();
565
+
566
+ // Determine how many flex lines are needed in this layout by measuring each child.
567
+ // (Expand or shrink the view depending on the flexGrow and flexShrink attributes in a later
568
+ // loop)
569
+ {
570
+ int childCount = getChildCount();
571
+ int paddingStart = ViewCompat.getPaddingStart(this);
572
+ int paddingEnd = ViewCompat.getPaddingEnd(this);
573
+ int largestHeightInRow = Integer.MIN_VALUE;
574
+ FlexLine flexLine = new FlexLine();
575
+
576
+ // The index of the view in a same flex line.
577
+ int indexInFlexLine = 0;
578
+ flexLine.mMainSize = paddingStart + paddingEnd;
579
+ for (int i = 0; i < childCount; i++) {
580
+ View child = getReorderedChildAt(i);
581
+ if (child == null) {
582
+ addFlexLineIfLastFlexItem(i, childCount, flexLine);
583
+ continue;
584
+ } else if (child.getVisibility() == View.GONE) {
585
+ flexLine.mItemCount++;
586
+ flexLine.mGoneItemCount++;
587
+ addFlexLineIfLastFlexItem(i, childCount, flexLine);
588
+ continue;
589
+ }
590
+
591
+ FlexboxLayout.LayoutParams lp = (LayoutParams) child.getLayoutParams();
592
+ if (lp.alignSelf == LayoutParams.ALIGN_SELF_STRETCH) {
593
+ flexLine.mIndicesAlignSelfStretch.add(i);
594
+ }
595
+
596
+ int childWidth = lp.width;
597
+ if (lp.flexBasisPercent != LayoutParams.FLEX_BASIS_PERCENT_DEFAULT
598
+ && widthMode == MeasureSpec.EXACTLY) {
599
+ childWidth = Math.round(widthSize * lp.flexBasisPercent);
600
+ // Use the dimension from the layout_width attribute if the widthMode is not
601
+ // MeasureSpec.EXACTLY even if any fraction value is set to
602
+ // layout_flexBasisPercent.
603
+ // There are likely quite few use cases where assigning any fraction values
604
+ // with widthMode is not MeasureSpec.EXACTLY (e.g. FlexboxLayout's layout_width
605
+ // is set to wrap_content)
606
+ }
607
+ int childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec,
608
+ getPaddingLeft() + getPaddingRight() + lp.leftMargin
609
+ + lp.rightMargin, childWidth < 0 ? LayoutParams.WRAP_CONTENT : childWidth);
610
+ int childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec,
611
+ getPaddingTop() + getPaddingBottom() + lp.topMargin
612
+ + lp.bottomMargin, lp.height < 0 ? LayoutParams.WRAP_CONTENT : lp.height);
613
+
614
+ child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
615
+
616
+ // Check the size constraint after the first measurement for the child
617
+ // To prevent the child's width/height violate the size constraints imposed by the
618
+ // {@link LayoutParams#minWidth}, {@link LayoutParams#minHeight},
619
+ // {@link LayoutParams#maxWidth} and {@link LayoutParams#maxHeight} attributes.
620
+ // E.g. When the child's layout_width is wrap_content the measured width may be
621
+ // less than the min width after the first measurement.
622
+ checkSizeConstraints(child);
623
+
624
+ childState = View.combineMeasuredStates(childState, child.getMeasuredState());
625
+ largestHeightInRow = Math.max(largestHeightInRow,
626
+ child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin);
627
+
628
+ if (isWrapRequired(widthMode, widthSize, flexLine.mMainSize,
629
+ child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin, lp,
630
+ i, indexInFlexLine)) {
631
+ if (flexLine.getLayoutVisibleItemCount() > 0) {
632
+ addFlexLine(flexLine);
633
+ }
634
+
635
+ flexLine = new FlexLine();
636
+ flexLine.mItemCount = 1;
637
+ flexLine.mMainSize = paddingStart + paddingEnd;
638
+ largestHeightInRow = child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;
639
+ indexInFlexLine = 0;
640
+ } else {
641
+ flexLine.mItemCount++;
642
+ indexInFlexLine++;
643
+ }
644
+ flexLine.mMainSize += child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin;
645
+ flexLine.mTotalFlexGrow += lp.flexGrow;
646
+ flexLine.mTotalFlexShrink += lp.flexShrink;
647
+ // Temporarily set the cross axis length as the largest child in the row
648
+ // Expand along the cross axis depending on the mAlignContent property if needed
649
+ // later
650
+ flexLine.mCrossSize = Math.max(flexLine.mCrossSize, largestHeightInRow);
651
+
652
+ // Check if the beginning or middle divider is required for the flex item
653
+ if (hasDividerBeforeChildAtAlongMainAxis(i, indexInFlexLine)) {
654
+ flexLine.mMainSize += mDividerVerticalWidth;
655
+ flexLine.mDividerLengthInMainSize += mDividerVerticalWidth;
656
+ }
657
+
658
+ if (mFlexWrap != FLEX_WRAP_WRAP_REVERSE) {
659
+ flexLine.mMaxBaseline = Math
660
+ .max(flexLine.mMaxBaseline, child.getBaseline() + lp.topMargin);
661
+ } else {
662
+ // if the flex wrap property is FLEX_WRAP_WRAP_REVERSE, calculate the
663
+ // baseline as the distance from the cross end and the baseline
664
+ // since the cross size calculation is based on the distance from the cross end
665
+ flexLine.mMaxBaseline = Math
666
+ .max(flexLine.mMaxBaseline,
667
+ child.getMeasuredHeight() - child.getBaseline()
668
+ + lp.bottomMargin);
669
+ }
670
+ addFlexLineIfLastFlexItem(i, childCount, flexLine);
671
+ }
672
+ }
673
+
674
+ determineMainSize(mFlexDirection, widthMeasureSpec, heightMeasureSpec);
675
+
676
+ // TODO: Consider the case any individual child's alignSelf is set to ALIGN_SELF_BASELINE
677
+ if (mAlignItems == ALIGN_ITEMS_BASELINE) {
678
+ int viewIndex = 0;
679
+ for (FlexLine flexLine : mFlexLines) {
680
+ // The largest height value that also take the baseline shift into account
681
+ int largestHeightInLine = Integer.MIN_VALUE;
682
+ for (int i = viewIndex; i < viewIndex + flexLine.mItemCount; i++) {
683
+ View child = getReorderedChildAt(i);
684
+ LayoutParams lp = (LayoutParams) child.getLayoutParams();
685
+
686
+ if (mFlexWrap != FLEX_WRAP_WRAP_REVERSE) {
687
+ int marginTop = flexLine.mMaxBaseline - child.getBaseline();
688
+ marginTop = Math.max(marginTop, lp.topMargin);
689
+ largestHeightInLine = Math.max(largestHeightInLine,
690
+ child.getMeasuredHeight() + marginTop + lp.bottomMargin);
691
+ } else {
692
+ int marginBottom = flexLine.mMaxBaseline - child.getMeasuredHeight() +
693
+ child.getBaseline();
694
+ marginBottom = Math.max(marginBottom, lp.bottomMargin);
695
+ largestHeightInLine = Math.max(largestHeightInLine,
696
+ child.getMeasuredHeight() + lp.topMargin + marginBottom);
697
+ }
698
+ }
699
+ flexLine.mCrossSize = largestHeightInLine;
700
+ viewIndex += flexLine.mItemCount;
701
+ }
702
+ }
703
+
704
+ determineCrossSize(mFlexDirection, widthMeasureSpec, heightMeasureSpec,
705
+ getPaddingTop() + getPaddingBottom());
706
+ // Now cross size for each flex line is determined.
707
+ // Expand the views if alignItems (or alignSelf in each child view) is set to stretch
708
+ stretchViews(mFlexDirection, mAlignItems);
709
+ setMeasuredDimensionForFlex(mFlexDirection, widthMeasureSpec, heightMeasureSpec,
710
+ childState);
711
+ }
712
+
713
+ /**
714
+ * Sub method for {@link #onMeasure(int, int)} when the main axis direction is vertical
715
+ * (either from top to bottom or bottom to top).
716
+ *
717
+ * @param widthMeasureSpec horizontal space requirements as imposed by the parent
718
+ * @param heightMeasureSpec vertical space requirements as imposed by the parent
719
+ * @see #onMeasure(int, int)
720
+ * @see #setFlexDirection(int)
721
+ * @see #setFlexWrap(int)
722
+ * @see #setAlignItems(int)
723
+ * @see #setAlignContent(int)
724
+ */
725
+ private void measureVertical(int widthMeasureSpec, int heightMeasureSpec) {
726
+ int heightMode = MeasureSpec.getMode(heightMeasureSpec);
727
+ int heightSize = MeasureSpec.getSize(heightMeasureSpec);
728
+ int childState = 0;
729
+
730
+ mFlexLines.clear();
731
+
732
+ // Determine how many flex lines are needed in this layout by measuring each child.
733
+ // (Expand or shrink the view depending on the flexGrow and flexShrink attributes in a later
734
+ // loop)
735
+ int childCount = getChildCount();
736
+ int paddingTop = getPaddingTop();
737
+ int paddingBottom = getPaddingBottom();
738
+ int largestWidthInColumn = Integer.MIN_VALUE;
739
+ FlexLine flexLine = new FlexLine();
740
+ flexLine.mMainSize = paddingTop + paddingBottom;
741
+ // The index of the view in a same flex line.
742
+ int indexInFlexLine = 0;
743
+ for (int i = 0; i < childCount; i++) {
744
+ View child = getReorderedChildAt(i);
745
+ if (child == null) {
746
+ addFlexLineIfLastFlexItem(i, childCount, flexLine);
747
+ continue;
748
+ } else if (child.getVisibility() == View.GONE) {
749
+ flexLine.mItemCount++;
750
+ flexLine.mGoneItemCount++;
751
+ addFlexLineIfLastFlexItem(i, childCount, flexLine);
752
+ continue;
753
+ }
754
+
755
+ FlexboxLayout.LayoutParams lp = (LayoutParams) child.getLayoutParams();
756
+ if (lp.alignSelf == LayoutParams.ALIGN_SELF_STRETCH) {
757
+ flexLine.mIndicesAlignSelfStretch.add(i);
758
+ }
759
+
760
+ int childHeight = lp.height;
761
+ if (lp.flexBasisPercent != LayoutParams.FLEX_BASIS_PERCENT_DEFAULT
762
+ && heightMode == MeasureSpec.EXACTLY) {
763
+ childHeight = Math.round(heightSize * lp.flexBasisPercent);
764
+ // Use the dimension from the layout_height attribute if the heightMode is not
765
+ // MeasureSpec.EXACTLY even if any fraction value is set to layout_flexBasisPercent.
766
+ // There are likely quite few use cases where assigning any fraction values
767
+ // with heightMode is not MeasureSpec.EXACTLY (e.g. FlexboxLayout's layout_height
768
+ // is set to wrap_content)
769
+ }
770
+
771
+ int childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec,
772
+ getPaddingLeft() + getPaddingRight() + lp.leftMargin
773
+ + lp.rightMargin, lp.width < 0 ? LayoutParams.WRAP_CONTENT : lp.width);
774
+ int childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec,
775
+ getPaddingTop() + getPaddingBottom() + lp.topMargin
776
+ + lp.bottomMargin, childHeight < 0 ? LayoutParams.WRAP_CONTENT : childHeight);
777
+
778
+ child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
779
+
780
+ // Check the size constraint after the first measurement for the child
781
+ // To prevent the child's width/height violate the size constraints imposed by the
782
+ // {@link LayoutParams#minWidth}, {@link LayoutParams#minHeight},
783
+ // {@link LayoutParams#maxWidth} and {@link LayoutParams#maxHeight} attributes.
784
+ // E.g. When the child's layout_height is wrap_content the measured height may be
785
+ // less than the min height after the first measurement.
786
+ checkSizeConstraints(child);
787
+
788
+ childState = View
789
+ .combineMeasuredStates(childState, child.getMeasuredState());
790
+ largestWidthInColumn = Math.max(largestWidthInColumn,
791
+ child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin);
792
+
793
+ if (isWrapRequired(heightMode, heightSize, flexLine.mMainSize,
794
+ child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin, lp,
795
+ i, indexInFlexLine)) {
796
+ if (flexLine.getLayoutVisibleItemCount() > 0) {
797
+ addFlexLine(flexLine);
798
+ }
799
+
800
+ flexLine = new FlexLine();
801
+ flexLine.mItemCount = 1;
802
+ flexLine.mMainSize = paddingTop + paddingBottom;
803
+ largestWidthInColumn = child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin;
804
+ indexInFlexLine = 0;
805
+ } else {
806
+ flexLine.mItemCount++;
807
+ indexInFlexLine++;
808
+ }
809
+ flexLine.mMainSize += child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;
810
+ flexLine.mTotalFlexGrow += lp.flexGrow;
811
+ flexLine.mTotalFlexShrink += lp.flexShrink;
812
+ // Temporarily set the cross axis length as the largest child width in the column
813
+ // Expand along the cross axis depending on the mAlignContent property if needed
814
+ // later
815
+ flexLine.mCrossSize = Math.max(flexLine.mCrossSize, largestWidthInColumn);
816
+
817
+ if (hasDividerBeforeChildAtAlongMainAxis(i, indexInFlexLine)) {
818
+ flexLine.mMainSize += mDividerHorizontalHeight;
819
+ }
820
+ addFlexLineIfLastFlexItem(i, childCount, flexLine);
821
+ }
822
+
823
+ determineMainSize(mFlexDirection, widthMeasureSpec, heightMeasureSpec);
824
+ determineCrossSize(mFlexDirection, widthMeasureSpec, heightMeasureSpec,
825
+ getPaddingLeft() + getPaddingRight());
826
+ // Now cross size for each flex line is determined.
827
+ // Expand the views if alignItems (or alignSelf in each child view) is set to stretch
828
+ stretchViews(mFlexDirection, mAlignItems);
829
+ setMeasuredDimensionForFlex(mFlexDirection, widthMeasureSpec, heightMeasureSpec,
830
+ childState);
831
+ }
832
+
833
+ /**
834
+ * Checks if the view's width/height don't violate the minimum/maximum size constraints imposed
835
+ * by the {@link LayoutParams#minWidth}, {@link LayoutParams#minHeight},
836
+ * {@link LayoutParams#maxWidth} and {@link LayoutParams#maxHeight} attributes.
837
+ *
838
+ * @param view the view to be checked
839
+ */
840
+ private void checkSizeConstraints(View view) {
841
+ boolean needsMeasure = false;
842
+ LayoutParams lp = (LayoutParams) view.getLayoutParams();
843
+ int childWidth = view.getMeasuredWidth();
844
+ int childHeight = view.getMeasuredHeight();
845
+
846
+ if (view.getMeasuredWidth() < lp.minWidth) {
847
+ needsMeasure = true;
848
+ childWidth = lp.minWidth;
849
+ } else if (view.getMeasuredWidth() > lp.maxWidth) {
850
+ needsMeasure = true;
851
+ childWidth = lp.maxWidth;
852
+ }
853
+
854
+ if (childHeight < lp.minHeight) {
855
+ needsMeasure = true;
856
+ childHeight = lp.minHeight;
857
+ } else if (childHeight > lp.maxHeight) {
858
+ needsMeasure = true;
859
+ childHeight = lp.maxHeight;
860
+ }
861
+ if (needsMeasure) {
862
+ view.measure(MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.EXACTLY),
863
+ MeasureSpec.makeMeasureSpec(childHeight, MeasureSpec.EXACTLY));
864
+ }
865
+ }
866
+
867
+ private void addFlexLineIfLastFlexItem(int childIndex, int childCount, FlexLine flexLine) {
868
+ if (childIndex == childCount - 1 && flexLine.getLayoutVisibleItemCount() != 0) {
869
+ // Add the flex line if this item is the last item
870
+ addFlexLine(flexLine);
871
+ }
872
+ }
873
+
874
+ private void addFlexLine(FlexLine flexLine) {
875
+ // The size of the end divider isn't added until the flexLine is added to the flex container
876
+ // take the divider width (or height) into account when adding the flex line.
877
+ if (isMainAxisDirectionHorizontal(mFlexDirection)) {
878
+ if ((mShowDividerVertical & SHOW_DIVIDER_END) > 0) {
879
+ flexLine.mMainSize += mDividerVerticalWidth;
880
+ flexLine.mDividerLengthInMainSize += mDividerVerticalWidth;
881
+ }
882
+ } else {
883
+ if ((mShowDividerHorizontal & SHOW_DIVIDER_END) > 0) {
884
+ flexLine.mMainSize += mDividerHorizontalHeight;
885
+ flexLine.mDividerLengthInMainSize += mDividerHorizontalHeight;
886
+ }
887
+ }
888
+ mFlexLines.add(flexLine);
889
+ }
890
+
891
+ /**
892
+ * Determine the main size by expanding (shrinking if negative remaining free space is given)
893
+ * an individual child in each flex line if any children's flexGrow (or flexShrink if remaining
894
+ * space is negative) properties are set to non-zero.
895
+ *
896
+ * @param flexDirection the value of the flex direction
897
+ * @param widthMeasureSpec horizontal space requirements as imposed by the parent
898
+ * @param heightMeasureSpec vertical space requirements as imposed by the parent
899
+ * @see #setFlexDirection(int)
900
+ * @see #getFlexDirection()
901
+ */
902
+ private void determineMainSize(@FlexDirection int flexDirection, int widthMeasureSpec,
903
+ int heightMeasureSpec) {
904
+ int mainSize;
905
+ int paddingAlongMainAxis;
906
+ switch (flexDirection) {
907
+ case FLEX_DIRECTION_ROW: // Intentional fall through
908
+ case FLEX_DIRECTION_ROW_REVERSE:
909
+ int widthMode = MeasureSpec.getMode(widthMeasureSpec);
910
+ int widthSize = MeasureSpec.getSize(widthMeasureSpec);
911
+ if (widthMode == MeasureSpec.EXACTLY) {
912
+ mainSize = widthSize;
913
+ } else {
914
+ mainSize = getLargestMainSize();
915
+ }
916
+ paddingAlongMainAxis = getPaddingLeft() + getPaddingRight();
917
+ break;
918
+ case FLEX_DIRECTION_COLUMN: // Intentional fall through
919
+ case FLEX_DIRECTION_COLUMN_REVERSE:
920
+ int heightMode = MeasureSpec.getMode(heightMeasureSpec);
921
+ int heightSize = MeasureSpec.getSize(heightMeasureSpec);
922
+ if (heightMode == MeasureSpec.EXACTLY) {
923
+ mainSize = heightSize;
924
+ } else {
925
+ mainSize = getLargestMainSize();
926
+ }
927
+ paddingAlongMainAxis = getPaddingTop() + getPaddingBottom();
928
+ break;
929
+ default:
930
+ throw new IllegalArgumentException("Invalid flex direction: " + flexDirection);
931
+ }
932
+
933
+ int childIndex = 0;
934
+ for (FlexLine flexLine : mFlexLines) {
935
+ if (flexLine.mMainSize < mainSize) {
936
+ childIndex = expandFlexItems(flexLine, flexDirection, mainSize,
937
+ paddingAlongMainAxis, childIndex);
938
+ } else {
939
+ childIndex = shrinkFlexItems(flexLine, flexDirection, mainSize,
940
+ paddingAlongMainAxis, childIndex);
941
+ }
942
+ }
943
+ }
944
+
945
+ /**
946
+ * Expand the flex items along the main axis based on the individual flexGrow attribute.
947
+ *
948
+ * @param flexLine the flex line to which flex items belong
949
+ * @param flexDirection the flexDirection value for this FlexboxLayout
950
+ * @param maxMainSize the maximum main size. Expanded main size will be this size
951
+ * @param paddingAlongMainAxis the padding value along the main axis
952
+ * @param startIndex the start index of the children views to be expanded. This index
953
+ * needs to
954
+ * be an absolute index in the flex container (FlexboxLayout),
955
+ * not the relative index in the flex line.
956
+ * @return the next index, the next flex line's first flex item starts from the returned index
957
+ * @see #getFlexDirection()
958
+ * @see #setFlexDirection(int)
959
+ * @see LayoutParams#flexGrow
960
+ */
961
+ private int expandFlexItems(FlexLine flexLine, @FlexDirection int flexDirection,
962
+ int maxMainSize, int paddingAlongMainAxis, int startIndex) {
963
+ int childIndex = startIndex;
964
+ if (flexLine.mTotalFlexGrow <= 0 || maxMainSize < flexLine.mMainSize) {
965
+ childIndex += flexLine.mItemCount;
966
+ return childIndex;
967
+ }
968
+ int sizeBeforeExpand = flexLine.mMainSize;
969
+ boolean needsReExpand = false;
970
+ float unitSpace = (maxMainSize - flexLine.mMainSize) / flexLine.mTotalFlexGrow;
971
+ flexLine.mMainSize = paddingAlongMainAxis + flexLine.mDividerLengthInMainSize;
972
+ float accumulatedRoundError = 0;
973
+ for (int i = 0; i < flexLine.mItemCount; i++) {
974
+ View child = getReorderedChildAt(childIndex);
975
+ if (child == null) {
976
+ continue;
977
+ } else if (child.getVisibility() == View.GONE) {
978
+ childIndex++;
979
+ continue;
980
+ }
981
+ LayoutParams lp = (LayoutParams) child.getLayoutParams();
982
+ if (isMainAxisDirectionHorizontal(flexDirection)) {
983
+ // The direction of the main axis is horizontal
984
+ if (!mChildrenFrozen[childIndex]) {
985
+ float rawCalculatedWidth = child.getMeasuredWidth() + unitSpace * lp.flexGrow + accumulatedRoundError;
986
+ int roundedCalculatedWidth = Math.round(rawCalculatedWidth);
987
+ if (roundedCalculatedWidth > lp.maxWidth) {
988
+ // This means the child can't expand beyond the value of the maxWidth attribute.
989
+ // To adjust the flex line length to the size of maxMainSize, remaining
990
+ // positive free space needs to be re-distributed to other flex items
991
+ // (children views). In that case, invoke this method again with the same
992
+ // startIndex.
993
+ needsReExpand = true;
994
+ roundedCalculatedWidth = lp.maxWidth;
995
+ mChildrenFrozen[childIndex] = true;
996
+ flexLine.mTotalFlexGrow -= lp.flexGrow;
997
+ } else {
998
+ accumulatedRoundError = (rawCalculatedWidth - roundedCalculatedWidth);
999
+ }
1000
+ child.measure(MeasureSpec.makeMeasureSpec(roundedCalculatedWidth, MeasureSpec.EXACTLY),
1001
+ MeasureSpec
1002
+ .makeMeasureSpec(child.getMeasuredHeight(),
1003
+ MeasureSpec.EXACTLY));
1004
+ }
1005
+ flexLine.mMainSize += child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin;
1006
+ } else {
1007
+ // The direction of the main axis is vertical
1008
+ if (!mChildrenFrozen[childIndex]) {
1009
+ float rawCalculatedHeight = child.getMeasuredHeight() + unitSpace * lp.flexGrow;
1010
+ int roundedCalculatedHeight = Math.round(rawCalculatedHeight);
1011
+ if (roundedCalculatedHeight > lp.maxHeight) {
1012
+ // This means the child can't expand beyond the value of the maxHeight
1013
+ // attribute.
1014
+ // To adjust the flex line length to the size of maxMainSize, remaining
1015
+ // positive free space needs to be re-distributed to other flex items
1016
+ // (children views). In that case, invoke this method again with the same
1017
+ // startIndex.
1018
+ needsReExpand = true;
1019
+ roundedCalculatedHeight = lp.maxHeight;
1020
+ mChildrenFrozen[childIndex] = true;
1021
+ flexLine.mTotalFlexGrow -= lp.flexGrow;
1022
+ } else {
1023
+ accumulatedRoundError = rawCalculatedHeight - roundedCalculatedHeight;
1024
+ }
1025
+ child.measure(MeasureSpec.makeMeasureSpec(child.getMeasuredWidth(),
1026
+ MeasureSpec.EXACTLY),
1027
+ MeasureSpec.makeMeasureSpec(roundedCalculatedHeight, MeasureSpec.EXACTLY));
1028
+ }
1029
+ flexLine.mMainSize += child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;
1030
+ }
1031
+ childIndex++;
1032
+ }
1033
+
1034
+ if (needsReExpand && sizeBeforeExpand != flexLine.mMainSize) {
1035
+ // Re-invoke the method with the same startIndex to distribute the positive free space
1036
+ // that wasn't fully distributed (because of maximum length constraint)
1037
+ expandFlexItems(flexLine, flexDirection, maxMainSize, paddingAlongMainAxis, startIndex);
1038
+ }
1039
+ return childIndex;
1040
+ }
1041
+
1042
+ /**
1043
+ * Shrink the flex items along the main axis based on the individual flexShrink attribute.
1044
+ *
1045
+ * @param flexLine the flex line to which flex items belong
1046
+ * @param flexDirection the flexDirection value for this FlexboxLayout
1047
+ * @param maxMainSize the maximum main size. Shrank main size will be this size
1048
+ * @param paddingAlongMainAxis the padding value along the main axis
1049
+ * @param startIndex the start index of the children views to be shrank. This index
1050
+ * needs to
1051
+ * be an absolute index in the flex container (FlexboxLayout),
1052
+ * not the relative index in the flex line.
1053
+ * @return the next index, the next flex line's first flex item starts from the returned index
1054
+ * @see #getFlexDirection()
1055
+ * @see #setFlexDirection(int)
1056
+ * @see LayoutParams#flexShrink
1057
+ */
1058
+ private int shrinkFlexItems(FlexLine flexLine, @FlexDirection int flexDirection,
1059
+ int maxMainSize, int paddingAlongMainAxis, int startIndex) {
1060
+ int childIndex = startIndex;
1061
+ int sizeBeforeShrink = flexLine.mMainSize;
1062
+ if (flexLine.mTotalFlexShrink <= 0 || maxMainSize > flexLine.mMainSize) {
1063
+ childIndex += flexLine.mItemCount;
1064
+ return childIndex;
1065
+ }
1066
+ boolean needsReShrink = false;
1067
+ float unitShrink = (flexLine.mMainSize - maxMainSize) / flexLine.mTotalFlexShrink;
1068
+ float accumulatedRoundError = 0;
1069
+ flexLine.mMainSize = paddingAlongMainAxis + flexLine.mDividerLengthInMainSize;
1070
+ for (int i = 0; i < flexLine.mItemCount; i++) {
1071
+ View child = getReorderedChildAt(childIndex);
1072
+ if (child == null) {
1073
+ continue;
1074
+ } else if (child.getVisibility() == View.GONE) {
1075
+ childIndex++;
1076
+ continue;
1077
+ }
1078
+ LayoutParams lp = (LayoutParams) child.getLayoutParams();
1079
+ if (isMainAxisDirectionHorizontal(flexDirection)) {
1080
+ // The direction of main axis is horizontal
1081
+ if (!mChildrenFrozen[childIndex]) {
1082
+ float rawCalculatedWidth = child.getMeasuredWidth() - unitShrink * lp.flexShrink + accumulatedRoundError;
1083
+ int roundedCalculatedWidth = Math.round(rawCalculatedWidth);
1084
+ if (roundedCalculatedWidth < lp.minWidth) {
1085
+ needsReShrink = true;
1086
+ roundedCalculatedWidth = lp.minWidth;
1087
+ mChildrenFrozen[childIndex] = true;
1088
+ flexLine.mTotalFlexShrink -= lp.flexShrink;
1089
+ } else {
1090
+ accumulatedRoundError = rawCalculatedWidth - roundedCalculatedWidth;
1091
+ }
1092
+
1093
+ int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(roundedCalculatedWidth, MeasureSpec.EXACTLY);
1094
+
1095
+ // NOTE: for controls that support internal content wrapping (e.g. TextView) reducing the width
1096
+ // might result in increased height e.g. text that could be shown on one line for larger
1097
+ // width needs to be wrapped in two when width is reduced.
1098
+ // As a result we cannot unconditionally measure with EXACTLY the current measured height
1099
+ int childHeightMeasureSpec = getChildMeasureSpec(this.getMeasuredHeightAndState(),
1100
+ getPaddingTop() + getPaddingBottom() + lp.topMargin
1101
+ + lp.bottomMargin, lp.height < 0 ? LayoutParams.WRAP_CONTENT : lp.height);
1102
+
1103
+ child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
1104
+
1105
+ // make sure crossSize is up-to-date as child calculated height might have increased
1106
+ flexLine.mCrossSize = Math.max(
1107
+ flexLine.mCrossSize,
1108
+ child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin
1109
+ );
1110
+ }
1111
+ flexLine.mMainSize += child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin;
1112
+ } else {
1113
+ // The direction of main axis is vertical
1114
+ if (!mChildrenFrozen[childIndex]) {
1115
+ float rawCalculatedHeight = child.getMeasuredHeight() - unitShrink * lp.flexShrink + accumulatedRoundError;
1116
+ int roundedCalculatedHeight = Math.round(rawCalculatedHeight);
1117
+ if (roundedCalculatedHeight < lp.minHeight) {
1118
+ needsReShrink = true;
1119
+ roundedCalculatedHeight = lp.minHeight;
1120
+ mChildrenFrozen[childIndex] = true;
1121
+ flexLine.mTotalFlexShrink -= lp.flexShrink;
1122
+ } else {
1123
+ accumulatedRoundError = rawCalculatedHeight - roundedCalculatedHeight;
1124
+ }
1125
+ child.measure(MeasureSpec.makeMeasureSpec(child.getMeasuredWidth(),
1126
+ MeasureSpec.EXACTLY),
1127
+ MeasureSpec.makeMeasureSpec(roundedCalculatedHeight, MeasureSpec.EXACTLY));
1128
+ }
1129
+ flexLine.mMainSize += child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;
1130
+ }
1131
+ childIndex++;
1132
+ }
1133
+
1134
+ if (needsReShrink && sizeBeforeShrink != flexLine.mMainSize) {
1135
+ // Re-invoke the method with the same startIndex to distribute the negative free space
1136
+ // that wasn't fully distributed (because some views length were not enough)
1137
+ shrinkFlexItems(flexLine, flexDirection, maxMainSize, paddingAlongMainAxis, startIndex);
1138
+ }
1139
+ return childIndex;
1140
+ }
1141
+
1142
+ /**
1143
+ * Determines the cross size (Calculate the length along the cross axis).
1144
+ * Expand the cross size only if the height mode is MeasureSpec.EXACTLY, otherwise
1145
+ * use the sum of cross sizes of all flex lines.
1146
+ *
1147
+ * @param flexDirection the flex direction attribute
1148
+ * @param widthMeasureSpec horizontal space requirements as imposed by the parent
1149
+ * @param heightMeasureSpec vertical space requirements as imposed by the parent
1150
+ * @param paddingAlongCrossAxis the padding value for the FlexboxLayout along the cross axis
1151
+ * @see #getFlexDirection()
1152
+ * @see #setFlexDirection(int)
1153
+ * @see #getAlignContent()
1154
+ * @see #setAlignContent(int)
1155
+ */
1156
+ private void determineCrossSize(int flexDirection, int widthMeasureSpec,
1157
+ int heightMeasureSpec, int paddingAlongCrossAxis) {
1158
+ // The MeasureSpec mode along the cross axis
1159
+ int mode;
1160
+ // The MeasureSpec size along the cross axis
1161
+ int size;
1162
+ switch (flexDirection) {
1163
+ case FLEX_DIRECTION_ROW: // Intentional fall through
1164
+ case FLEX_DIRECTION_ROW_REVERSE:
1165
+ mode = MeasureSpec.getMode(heightMeasureSpec);
1166
+ size = MeasureSpec.getSize(heightMeasureSpec);
1167
+ break;
1168
+ case FLEX_DIRECTION_COLUMN: // Intentional fall through
1169
+ case FLEX_DIRECTION_COLUMN_REVERSE:
1170
+ mode = MeasureSpec.getMode(widthMeasureSpec);
1171
+ size = MeasureSpec.getSize(widthMeasureSpec);
1172
+ break;
1173
+ default:
1174
+ throw new IllegalArgumentException("Invalid flex direction: " + flexDirection);
1175
+ }
1176
+ if (mode == MeasureSpec.EXACTLY) {
1177
+ int totalCrossSize = getSumOfCrossSize() + paddingAlongCrossAxis;
1178
+ if (mFlexLines.size() == 1) {
1179
+ mFlexLines.get(0).mCrossSize = size - paddingAlongCrossAxis;
1180
+ // alignContent property is valid only if the Flexbox has at least two lines
1181
+ } else if (mFlexLines.size() >= 2 && totalCrossSize < size) {
1182
+ switch (mAlignContent) {
1183
+ case ALIGN_CONTENT_STRETCH: {
1184
+ float freeSpaceUnit = (size - totalCrossSize) / (float) mFlexLines.size();
1185
+ float accumulatedError = 0;
1186
+ for (int i = 0, flexLinesSize = mFlexLines.size(); i < flexLinesSize; i++) {
1187
+ FlexLine flexLine = mFlexLines.get(i);
1188
+ float newCrossSizeAsFloat = flexLine.mCrossSize + freeSpaceUnit;
1189
+ if (i == mFlexLines.size() - 1) {
1190
+ newCrossSizeAsFloat += accumulatedError;
1191
+ accumulatedError = 0;
1192
+ }
1193
+ int newCrossSize = Math.round(newCrossSizeAsFloat);
1194
+ accumulatedError += (newCrossSizeAsFloat - newCrossSize);
1195
+ if (accumulatedError > 1) {
1196
+ newCrossSize += 1;
1197
+ accumulatedError -= 1;
1198
+ } else if (accumulatedError < -1) {
1199
+ newCrossSize -= 1;
1200
+ accumulatedError += 1;
1201
+ }
1202
+ flexLine.mCrossSize = newCrossSize;
1203
+ }
1204
+ break;
1205
+ }
1206
+ case ALIGN_CONTENT_SPACE_AROUND: {
1207
+ // The value of free space along the cross axis which needs to be put on top
1208
+ // and below the bottom of each flex line.
1209
+ int spaceTopAndBottom = size - totalCrossSize;
1210
+ // The number of spaces along the cross axis
1211
+ int numberOfSpaces = mFlexLines.size() * 2;
1212
+ spaceTopAndBottom = spaceTopAndBottom / numberOfSpaces;
1213
+ List<FlexLine> newFlexLines = new ArrayList<>();
1214
+ FlexLine dummySpaceFlexLine = new FlexLine();
1215
+ dummySpaceFlexLine.mCrossSize = spaceTopAndBottom;
1216
+ for (FlexLine flexLine : mFlexLines) {
1217
+ newFlexLines.add(dummySpaceFlexLine);
1218
+ newFlexLines.add(flexLine);
1219
+ newFlexLines.add(dummySpaceFlexLine);
1220
+ }
1221
+ mFlexLines = newFlexLines;
1222
+ break;
1223
+ }
1224
+ case ALIGN_CONTENT_SPACE_BETWEEN: {
1225
+ // The value of free space along the cross axis between each flex line.
1226
+ float spaceBetweenFlexLine = size - totalCrossSize;
1227
+ int numberOfSpaces = mFlexLines.size() - 1;
1228
+ spaceBetweenFlexLine = spaceBetweenFlexLine / (float) numberOfSpaces;
1229
+ float accumulatedError = 0;
1230
+ List<FlexLine> newFlexLines = new ArrayList<>();
1231
+ for (int i = 0, flexLineSize = mFlexLines.size(); i < flexLineSize; i++) {
1232
+ FlexLine flexLine = mFlexLines.get(i);
1233
+ newFlexLines.add(flexLine);
1234
+
1235
+ if (i != mFlexLines.size() - 1) {
1236
+ FlexLine dummySpaceFlexLine = new FlexLine();
1237
+ if (i == mFlexLines.size() - 2) {
1238
+ // The last dummy space block in the flex container.
1239
+ // Adjust the cross size by the accumulated error.
1240
+ dummySpaceFlexLine.mCrossSize = Math
1241
+ .round(spaceBetweenFlexLine + accumulatedError);
1242
+ accumulatedError = 0;
1243
+ } else {
1244
+ dummySpaceFlexLine.mCrossSize = Math
1245
+ .round(spaceBetweenFlexLine);
1246
+ }
1247
+ accumulatedError += (spaceBetweenFlexLine
1248
+ - dummySpaceFlexLine.mCrossSize);
1249
+ if (accumulatedError > 1) {
1250
+ dummySpaceFlexLine.mCrossSize += 1;
1251
+ accumulatedError -= 1;
1252
+ } else if (accumulatedError < -1) {
1253
+ dummySpaceFlexLine.mCrossSize -= 1;
1254
+ accumulatedError += 1;
1255
+ }
1256
+ newFlexLines.add(dummySpaceFlexLine);
1257
+ }
1258
+ }
1259
+ mFlexLines = newFlexLines;
1260
+ break;
1261
+ }
1262
+ case ALIGN_CONTENT_CENTER: {
1263
+ int spaceAboveAndBottom = size - totalCrossSize;
1264
+ spaceAboveAndBottom = spaceAboveAndBottom / 2;
1265
+ List<FlexLine> newFlexLines = new ArrayList<>();
1266
+ FlexLine dummySpaceFlexLine = new FlexLine();
1267
+ dummySpaceFlexLine.mCrossSize = spaceAboveAndBottom;
1268
+ for (int i = 0, flexLineSize = mFlexLines.size(); i < flexLineSize; i++) {
1269
+ if (i == 0) {
1270
+ newFlexLines.add(dummySpaceFlexLine);
1271
+ }
1272
+ FlexLine flexLine = mFlexLines.get(i);
1273
+ newFlexLines.add(flexLine);
1274
+ if (i == mFlexLines.size() - 1) {
1275
+ newFlexLines.add(dummySpaceFlexLine);
1276
+ }
1277
+ }
1278
+ mFlexLines = newFlexLines;
1279
+ break;
1280
+ }
1281
+ case ALIGN_CONTENT_FLEX_END: {
1282
+ int spaceTop = size - totalCrossSize;
1283
+ FlexLine dummySpaceFlexLine = new FlexLine();
1284
+ dummySpaceFlexLine.mCrossSize = spaceTop;
1285
+ mFlexLines.add(0, dummySpaceFlexLine);
1286
+ break;
1287
+ }
1288
+ }
1289
+ }
1290
+ }
1291
+ }
1292
+
1293
+ /**
1294
+ * Expand the view if the {@link #mAlignItems} attribute is set to {@link #ALIGN_ITEMS_STRETCH}
1295
+ * or {@link LayoutParams#ALIGN_SELF_STRETCH} is set to an individual child view.
1296
+ *
1297
+ * @param flexDirection the flex direction attribute
1298
+ * @param alignItems the align items attribute
1299
+ * @see #getFlexDirection()
1300
+ * @see #setFlexDirection(int)
1301
+ * @see #getAlignItems()
1302
+ * @see #setAlignItems(int)
1303
+ * @see LayoutParams#alignSelf
1304
+ */
1305
+ private void stretchViews(int flexDirection, int alignItems) {
1306
+ if (alignItems == ALIGN_ITEMS_STRETCH) {
1307
+ int viewIndex = 0;
1308
+ for (FlexLine flexLine : mFlexLines) {
1309
+ for (int i = 0; i < flexLine.mItemCount; i++, viewIndex++) {
1310
+ View view = getReorderedChildAt(viewIndex);
1311
+ LayoutParams lp = (LayoutParams) view.getLayoutParams();
1312
+ if (lp.alignSelf != LayoutParams.ALIGN_SELF_AUTO &&
1313
+ lp.alignSelf != LayoutParams.ALIGN_SELF_STRETCH) {
1314
+ continue;
1315
+ }
1316
+ switch (flexDirection) {
1317
+ case FLEX_DIRECTION_ROW: // Intentional fall through
1318
+ case FLEX_DIRECTION_ROW_REVERSE:
1319
+ stretchViewVertically(view, flexLine.mCrossSize);
1320
+ break;
1321
+ case FLEX_DIRECTION_COLUMN:
1322
+ case FLEX_DIRECTION_COLUMN_REVERSE:
1323
+ stretchViewHorizontally(view, flexLine.mCrossSize);
1324
+ break;
1325
+ default:
1326
+ throw new IllegalArgumentException(
1327
+ "Invalid flex direction: " + flexDirection);
1328
+ }
1329
+ }
1330
+ }
1331
+ } else {
1332
+ for (FlexLine flexLine : mFlexLines) {
1333
+ for (Integer index : flexLine.mIndicesAlignSelfStretch) {
1334
+ View view = getReorderedChildAt(index);
1335
+ switch (flexDirection) {
1336
+ case FLEX_DIRECTION_ROW: // Intentional fall through
1337
+ case FLEX_DIRECTION_ROW_REVERSE:
1338
+ stretchViewVertically(view, flexLine.mCrossSize);
1339
+ break;
1340
+ case FLEX_DIRECTION_COLUMN:
1341
+ case FLEX_DIRECTION_COLUMN_REVERSE:
1342
+ stretchViewHorizontally(view, flexLine.mCrossSize);
1343
+ break;
1344
+ default:
1345
+ throw new IllegalArgumentException(
1346
+ "Invalid flex direction: " + flexDirection);
1347
+ }
1348
+ }
1349
+ }
1350
+ }
1351
+ }
1352
+
1353
+ /**
1354
+ * Expand the view vertically to the size of the crossSize (considering the view margins)
1355
+ *
1356
+ * @param view the View to be stretched
1357
+ * @param crossSize the cross size
1358
+ */
1359
+ private void stretchViewVertically(View view, int crossSize) {
1360
+ LayoutParams lp = (LayoutParams) view.getLayoutParams();
1361
+ int newHeight = crossSize - lp.topMargin - lp.bottomMargin;
1362
+ newHeight = Math.max(newHeight, 0);
1363
+ view.measure(MeasureSpec
1364
+ .makeMeasureSpec(view.getMeasuredWidth(), MeasureSpec.EXACTLY),
1365
+ MeasureSpec.makeMeasureSpec(newHeight, MeasureSpec.EXACTLY));
1366
+ }
1367
+
1368
+ /**
1369
+ * Expand the view horizontally to the size of the crossSize (considering the view margins)
1370
+ *
1371
+ * @param view the View to be stretched
1372
+ * @param crossSize the cross size
1373
+ */
1374
+ private void stretchViewHorizontally(View view, int crossSize) {
1375
+ LayoutParams lp = (LayoutParams) view.getLayoutParams();
1376
+ int newWidth = crossSize - lp.leftMargin - lp.rightMargin;
1377
+ newWidth = Math.max(newWidth, 0);
1378
+ view.measure(MeasureSpec
1379
+ .makeMeasureSpec(newWidth, MeasureSpec.EXACTLY),
1380
+ MeasureSpec.makeMeasureSpec(view.getMeasuredHeight(), MeasureSpec.EXACTLY));
1381
+ }
1382
+
1383
+ /**
1384
+ * Set this FlexboxLayouts' width and height depending on the calculated size of main axis and
1385
+ * cross axis.
1386
+ *
1387
+ * @param flexDirection the value of the flex direction
1388
+ * @param widthMeasureSpec horizontal space requirements as imposed by the parent
1389
+ * @param heightMeasureSpec vertical space requirements as imposed by the parent
1390
+ * @param childState the child state of the View
1391
+ * @see #getFlexDirection()
1392
+ * @see #setFlexDirection(int)
1393
+ */
1394
+ private void setMeasuredDimensionForFlex(@FlexDirection int flexDirection, int widthMeasureSpec,
1395
+ int heightMeasureSpec, int childState) {
1396
+ int widthMode = MeasureSpec.getMode(widthMeasureSpec);
1397
+ int widthSize = MeasureSpec.getSize(widthMeasureSpec);
1398
+ int heightMode = MeasureSpec.getMode(heightMeasureSpec);
1399
+ int heightSize = MeasureSpec.getSize(heightMeasureSpec);
1400
+ int calculatedMaxHeight;
1401
+ int calculatedMaxWidth;
1402
+ switch (flexDirection) {
1403
+ case FLEX_DIRECTION_ROW: // Intentional fall through
1404
+ case FLEX_DIRECTION_ROW_REVERSE:
1405
+ calculatedMaxHeight = getSumOfCrossSize() + getPaddingTop()
1406
+ + getPaddingBottom();
1407
+ calculatedMaxWidth = getLargestMainSize();
1408
+ break;
1409
+ case FLEX_DIRECTION_COLUMN: // Intentional fall through
1410
+ case FLEX_DIRECTION_COLUMN_REVERSE:
1411
+ calculatedMaxHeight = getLargestMainSize();
1412
+ calculatedMaxWidth = getSumOfCrossSize() + getPaddingLeft() + getPaddingRight();
1413
+ break;
1414
+ default:
1415
+ throw new IllegalArgumentException("Invalid flex direction: " + flexDirection);
1416
+ }
1417
+
1418
+ int widthSizeAndState;
1419
+ switch (widthMode) {
1420
+ case MeasureSpec.EXACTLY:
1421
+ if (widthSize < calculatedMaxWidth) {
1422
+ childState = View
1423
+ .combineMeasuredStates(childState, View.MEASURED_STATE_TOO_SMALL);
1424
+ }
1425
+ widthSizeAndState = View.resolveSizeAndState(widthSize, widthMeasureSpec,
1426
+ childState);
1427
+ break;
1428
+ case MeasureSpec.AT_MOST: {
1429
+ if (widthSize < calculatedMaxWidth) {
1430
+ childState = View
1431
+ .combineMeasuredStates(childState, View.MEASURED_STATE_TOO_SMALL);
1432
+ } else {
1433
+ widthSize = calculatedMaxWidth;
1434
+ }
1435
+ widthSizeAndState = View.resolveSizeAndState(widthSize, widthMeasureSpec,
1436
+ childState);
1437
+ break;
1438
+ }
1439
+ case MeasureSpec.UNSPECIFIED: {
1440
+ widthSizeAndState = View
1441
+ .resolveSizeAndState(calculatedMaxWidth, widthMeasureSpec, childState);
1442
+ break;
1443
+ }
1444
+ default:
1445
+ throw new IllegalStateException("Unknown width mode is set: " + widthMode);
1446
+ }
1447
+ int heightSizeAndState;
1448
+ switch (heightMode) {
1449
+ case MeasureSpec.EXACTLY:
1450
+ if (heightSize < calculatedMaxHeight) {
1451
+ childState = View.combineMeasuredStates(childState,
1452
+ View.MEASURED_STATE_TOO_SMALL
1453
+ >> View.MEASURED_HEIGHT_STATE_SHIFT);
1454
+ }
1455
+ heightSizeAndState = View.resolveSizeAndState(heightSize, heightMeasureSpec,
1456
+ childState);
1457
+ break;
1458
+ case MeasureSpec.AT_MOST: {
1459
+ if (heightSize < calculatedMaxHeight) {
1460
+ childState = View.combineMeasuredStates(childState,
1461
+ View.MEASURED_STATE_TOO_SMALL
1462
+ >> View.MEASURED_HEIGHT_STATE_SHIFT);
1463
+ } else {
1464
+ heightSize = calculatedMaxHeight;
1465
+ }
1466
+ heightSizeAndState = View.resolveSizeAndState(heightSize, heightMeasureSpec,
1467
+ childState);
1468
+ break;
1469
+ }
1470
+ case MeasureSpec.UNSPECIFIED: {
1471
+ heightSizeAndState = View.resolveSizeAndState(calculatedMaxHeight,
1472
+ heightMeasureSpec, childState);
1473
+ break;
1474
+ }
1475
+ default:
1476
+ throw new IllegalStateException("Unknown height mode is set: " + heightMode);
1477
+ }
1478
+ setMeasuredDimension(widthSizeAndState, heightSizeAndState);
1479
+ }
1480
+
1481
+ /**
1482
+ * Determine if a wrap is required (add a new flex line).
1483
+ *
1484
+ * @param mode the width or height mode along the main axis direction
1485
+ * @param maxSize the max size along the main axis direction
1486
+ * @param currentLength the accumulated current length
1487
+ * @param childLength the length of a child view which is to be collected to the flex line
1488
+ * @param lp the LayoutParams for the view being determined whether a new flex line
1489
+ * is needed
1490
+ * @return {@code true} if a wrap is required, {@code false} otherwise
1491
+ * @see #getFlexWrap()
1492
+ * @see #setFlexWrap(int)
1493
+ */
1494
+ private boolean isWrapRequired(int mode, int maxSize, int currentLength, int childLength,
1495
+ LayoutParams lp, int childAbsoluteIndex, int childRelativeIndexInFlexLine) {
1496
+ if (mFlexWrap == FLEX_WRAP_NOWRAP) {
1497
+ return false;
1498
+ }
1499
+ if (lp.wrapBefore) {
1500
+ return true;
1501
+ }
1502
+ if (mode == MeasureSpec.UNSPECIFIED) {
1503
+ return false;
1504
+ }
1505
+ if (isMainAxisDirectionHorizontal(mFlexDirection)) {
1506
+ if (hasDividerBeforeChildAtAlongMainAxis(childAbsoluteIndex,
1507
+ childRelativeIndexInFlexLine)) {
1508
+ childLength += mDividerVerticalWidth;
1509
+ }
1510
+ if ((mShowDividerVertical & SHOW_DIVIDER_END) > 0) {
1511
+ childLength += mDividerVerticalWidth;
1512
+ }
1513
+ } else {
1514
+ if (hasDividerBeforeChildAtAlongMainAxis(childAbsoluteIndex,
1515
+ childRelativeIndexInFlexLine)) {
1516
+ childLength += mDividerHorizontalHeight;
1517
+ }
1518
+ if ((mShowDividerHorizontal & SHOW_DIVIDER_END) > 0) {
1519
+ childLength += mDividerHorizontalHeight;
1520
+ }
1521
+ }
1522
+ return maxSize < currentLength + childLength;
1523
+ }
1524
+
1525
+ /**
1526
+ * Retrieve the largest main size of all flex lines.
1527
+ *
1528
+ * @return the largest main size
1529
+ */
1530
+ private int getLargestMainSize() {
1531
+ int largestSize = Integer.MIN_VALUE;
1532
+ for (FlexLine flexLine : mFlexLines) {
1533
+ largestSize = Math.max(largestSize, flexLine.mMainSize);
1534
+ }
1535
+ return largestSize;
1536
+ }
1537
+
1538
+ /**
1539
+ * Retrieve the sum of the cross sizes of all flex lines including divider lengths.
1540
+ *
1541
+ * @return the sum of the cross sizes
1542
+ */
1543
+ private int getSumOfCrossSize() {
1544
+ int sum = 0;
1545
+ for (int i = 0, size = mFlexLines.size(); i < size; i++) {
1546
+ FlexLine flexLine = mFlexLines.get(i);
1547
+
1548
+ // Judge if the beginning or middle dividers are required
1549
+ if (hasDividerBeforeFlexLine(i)) {
1550
+ if (isMainAxisDirectionHorizontal(mFlexDirection)) {
1551
+ sum += mDividerHorizontalHeight;
1552
+ } else {
1553
+ sum += mDividerVerticalWidth;
1554
+ }
1555
+ }
1556
+
1557
+ // Judge if the end divider is required
1558
+ if (hasEndDividerAfterFlexLine(i)) {
1559
+ if (isMainAxisDirectionHorizontal(mFlexDirection)) {
1560
+ sum += mDividerHorizontalHeight;
1561
+ } else {
1562
+ sum += mDividerVerticalWidth;
1563
+ }
1564
+ }
1565
+ sum += flexLine.mCrossSize;
1566
+ }
1567
+ return sum;
1568
+ }
1569
+
1570
+ private boolean isMainAxisDirectionHorizontal(@FlexDirection int flexDirection) {
1571
+ return flexDirection == FLEX_DIRECTION_ROW
1572
+ || flexDirection == FLEX_DIRECTION_ROW_REVERSE;
1573
+ }
1574
+
1575
+ @Override
1576
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
1577
+ int layoutDirection = ViewCompat.getLayoutDirection(this);
1578
+ boolean isRtl;
1579
+ switch (mFlexDirection) {
1580
+ case FLEX_DIRECTION_ROW:
1581
+ isRtl = layoutDirection == ViewCompat.LAYOUT_DIRECTION_RTL;
1582
+ layoutHorizontal(isRtl, left, top, right, bottom);
1583
+ break;
1584
+ case FLEX_DIRECTION_ROW_REVERSE:
1585
+ isRtl = layoutDirection != ViewCompat.LAYOUT_DIRECTION_RTL;
1586
+ layoutHorizontal(isRtl, left, top, right, bottom);
1587
+ break;
1588
+ case FLEX_DIRECTION_COLUMN:
1589
+ isRtl = layoutDirection == ViewCompat.LAYOUT_DIRECTION_RTL;
1590
+ if (mFlexWrap == FLEX_WRAP_WRAP_REVERSE) {
1591
+ isRtl = !isRtl;
1592
+ }
1593
+ layoutVertical(isRtl, false, left, top, right, bottom);
1594
+ break;
1595
+ case FLEX_DIRECTION_COLUMN_REVERSE:
1596
+ isRtl = layoutDirection == ViewCompat.LAYOUT_DIRECTION_RTL;
1597
+ if (mFlexWrap == FLEX_WRAP_WRAP_REVERSE) {
1598
+ isRtl = !isRtl;
1599
+ }
1600
+ layoutVertical(isRtl, true, left, top, right, bottom);
1601
+ break;
1602
+ default:
1603
+ throw new IllegalStateException("Invalid flex direction is set: " + mFlexDirection);
1604
+ }
1605
+
1606
+ CommonLayoutParams.restoreOriginalParams(this);
1607
+ }
1608
+
1609
+ /**
1610
+ * Sub method for {@link #onLayout(boolean, int, int, int, int)} when the
1611
+ * {@link #mFlexDirection} is either {@link #FLEX_DIRECTION_ROW} or
1612
+ * {@link #FLEX_DIRECTION_ROW_REVERSE}.
1613
+ *
1614
+ * @param isRtl {@code true} if the horizontal layout direction is right to left, {@code
1615
+ * false} otherwise.
1616
+ * @param left the left position of this View
1617
+ * @param top the top position of this View
1618
+ * @param right the right position of this View
1619
+ * @param bottom the bottom position of this View
1620
+ * @see #getFlexWrap()
1621
+ * @see #setFlexWrap(int)
1622
+ * @see #getJustifyContent()
1623
+ * @see #setJustifyContent(int)
1624
+ * @see #getAlignItems()
1625
+ * @see #setAlignItems(int)
1626
+ * @see LayoutParams#alignSelf
1627
+ */
1628
+ private void layoutHorizontal(boolean isRtl, int left, int top, int right, int bottom) {
1629
+ int paddingLeft = getPaddingLeft();
1630
+ int paddingRight = getPaddingRight();
1631
+ // Use float to reduce the round error that may happen in when justifyContent ==
1632
+ // SPACE_BETWEEN or SPACE_AROUND
1633
+ float childLeft;
1634
+ int currentViewIndex = 0;
1635
+
1636
+ int height = bottom - top;
1637
+ int width = right - left;
1638
+ // childBottom is used if the mFlexWrap is FLEX_WRAP_WRAP_REVERSE otherwise
1639
+ // childTop is used to align the vertical position of the children views.
1640
+ int childBottom = height - getPaddingBottom();
1641
+ int childTop = getPaddingTop();
1642
+
1643
+ // Used only for RTL layout
1644
+ // Use float to reduce the round error that may happen in when justifyContent ==
1645
+ // SPACE_BETWEEN or SPACE_AROUND
1646
+ float childRight;
1647
+ for (int i = 0, size = mFlexLines.size(); i < size; i++) {
1648
+ FlexLine flexLine = mFlexLines.get(i);
1649
+ if (hasDividerBeforeFlexLine(i)) {
1650
+ childBottom -= mDividerHorizontalHeight;
1651
+ childTop += mDividerHorizontalHeight;
1652
+ }
1653
+ float spaceBetweenItem = 0f;
1654
+ switch (mJustifyContent) {
1655
+ case JUSTIFY_CONTENT_FLEX_START:
1656
+ childLeft = paddingLeft;
1657
+ childRight = width - paddingRight;
1658
+ break;
1659
+ case JUSTIFY_CONTENT_FLEX_END:
1660
+ childLeft = width - flexLine.mMainSize + paddingRight;
1661
+ childRight = flexLine.mMainSize - paddingLeft;
1662
+ break;
1663
+ case JUSTIFY_CONTENT_CENTER:
1664
+ childLeft = paddingLeft + (width - flexLine.mMainSize) / 2f;
1665
+ childRight = width - paddingRight - (width - flexLine.mMainSize) / 2f;
1666
+ break;
1667
+ case JUSTIFY_CONTENT_SPACE_AROUND: {
1668
+ int visibleCount = flexLine.getLayoutVisibleItemCount();
1669
+ if (visibleCount != 0) {
1670
+ spaceBetweenItem = (width - flexLine.mMainSize)
1671
+ / (float) visibleCount;
1672
+ }
1673
+ childLeft = paddingLeft + spaceBetweenItem / 2f;
1674
+ childRight = width - paddingRight - spaceBetweenItem / 2f;
1675
+ break;
1676
+ }
1677
+ case JUSTIFY_CONTENT_SPACE_BETWEEN: {
1678
+ int visibleCount = flexLine.getLayoutVisibleItemCount();
1679
+ float denominator = visibleCount != 1 ? visibleCount - 1 : 1f;
1680
+
1681
+ childLeft = paddingLeft;
1682
+ spaceBetweenItem = (width - flexLine.mMainSize) / denominator;
1683
+ childRight = width - paddingRight;
1684
+ break;
1685
+ }
1686
+ default:
1687
+ throw new IllegalStateException(
1688
+ "Invalid justifyContent is set: " + mJustifyContent);
1689
+ }
1690
+ spaceBetweenItem = Math.max(spaceBetweenItem, 0);
1691
+
1692
+ for (int j = 0; j < flexLine.mItemCount; j++) {
1693
+ View child = getReorderedChildAt(currentViewIndex);
1694
+ if (child == null) {
1695
+ continue;
1696
+ } else if (child.getVisibility() == View.GONE) {
1697
+ currentViewIndex++;
1698
+ continue;
1699
+ }
1700
+ LayoutParams lp = ((LayoutParams) child.getLayoutParams());
1701
+ childLeft += lp.leftMargin;
1702
+ childRight -= lp.rightMargin;
1703
+ if (hasDividerBeforeChildAtAlongMainAxis(currentViewIndex, j)) {
1704
+ childLeft += mDividerVerticalWidth;
1705
+ childRight -= mDividerVerticalWidth;
1706
+ }
1707
+
1708
+ if (mFlexWrap == FLEX_WRAP_WRAP_REVERSE) {
1709
+ if (isRtl) {
1710
+ layoutSingleChildHorizontal(child, flexLine, mFlexWrap, mAlignItems,
1711
+ Math.round(childRight) - child.getMeasuredWidth(),
1712
+ childBottom - child.getMeasuredHeight(), Math.round(childRight),
1713
+ childBottom);
1714
+ } else {
1715
+ layoutSingleChildHorizontal(child, flexLine, mFlexWrap, mAlignItems,
1716
+ Math.round(childLeft), childBottom - child.getMeasuredHeight(),
1717
+ Math.round(childLeft) + child.getMeasuredWidth(),
1718
+ childBottom);
1719
+ }
1720
+ } else {
1721
+ if (isRtl) {
1722
+ layoutSingleChildHorizontal(child, flexLine, mFlexWrap, mAlignItems,
1723
+ Math.round(childRight) - child.getMeasuredWidth(), childTop,
1724
+ Math.round(childRight), childTop + child.getMeasuredHeight());
1725
+ } else {
1726
+ layoutSingleChildHorizontal(child, flexLine, mFlexWrap, mAlignItems,
1727
+ Math.round(childLeft), childTop,
1728
+ Math.round(childLeft) + child.getMeasuredWidth(),
1729
+ childTop + child.getMeasuredHeight());
1730
+ }
1731
+ }
1732
+ childLeft += child.getMeasuredWidth() + spaceBetweenItem + lp.rightMargin;
1733
+ childRight -= child.getMeasuredWidth() + spaceBetweenItem + lp.leftMargin;
1734
+ currentViewIndex++;
1735
+
1736
+ flexLine.mLeft = Math.min(flexLine.mLeft, child.getLeft() - lp.leftMargin);
1737
+ flexLine.mTop = Math.min(flexLine.mTop, child.getTop() - lp.topMargin);
1738
+ flexLine.mRight = Math.max(flexLine.mRight, child.getRight() + lp.rightMargin);
1739
+ flexLine.mBottom = Math.max(flexLine.mBottom, child.getBottom() + lp.bottomMargin);
1740
+ }
1741
+ childTop += flexLine.mCrossSize;
1742
+ childBottom -= flexLine.mCrossSize;
1743
+ }
1744
+ }
1745
+
1746
+ /**
1747
+ * Place a single View when the layout direction is horizontal ({@link #mFlexDirection} is
1748
+ * either {@link #FLEX_DIRECTION_ROW} or {@link #FLEX_DIRECTION_ROW_REVERSE}).
1749
+ *
1750
+ * @param view the View to be placed
1751
+ * @param flexLine the {@link FlexLine} where the View belongs to
1752
+ * @param flexWrap the flex wrap attribute of this FlexboxLayout
1753
+ * @param alignItems the align items attribute of this FlexboxLayout
1754
+ * @param left the left position of the View, which the View's margin is already taken
1755
+ * into account
1756
+ * @param top the top position of the flex line where the View belongs to. The actual
1757
+ * View's top position is shifted depending on the flexWrap and alignItems
1758
+ * attributes
1759
+ * @param right the right position of the View, which the View's margin is already taken
1760
+ * into account
1761
+ * @param bottom the bottom position of the flex line where the View belongs to. The actual
1762
+ * View's bottom position is shifted depending on the flexWrap and alignItems
1763
+ * attributes
1764
+ * @see #getAlignItems()
1765
+ * @see #setAlignItems(int)
1766
+ * @see LayoutParams#alignSelf
1767
+ */
1768
+ private void layoutSingleChildHorizontal(View view, FlexLine flexLine, @FlexWrap int flexWrap,
1769
+ int alignItems, int left, int top, int right, int bottom) {
1770
+ LayoutParams lp = (LayoutParams) view.getLayoutParams();
1771
+ if (lp.alignSelf != LayoutParams.ALIGN_SELF_AUTO) {
1772
+ // Expecting the values for alignItems and alignSelf match except for ALIGN_SELF_AUTO.
1773
+ // Assigning the alignSelf value as alignItems should work.
1774
+ alignItems = lp.alignSelf;
1775
+ }
1776
+ int crossSize = flexLine.mCrossSize;
1777
+ switch (alignItems) {
1778
+ case ALIGN_ITEMS_FLEX_START: // Intentional fall through
1779
+ case ALIGN_ITEMS_STRETCH:
1780
+ if (flexWrap != FLEX_WRAP_WRAP_REVERSE) {
1781
+ view.layout(left, top + lp.topMargin, right, bottom + lp.topMargin);
1782
+ } else {
1783
+ view.layout(left, top - lp.bottomMargin, right, bottom - lp.bottomMargin);
1784
+ }
1785
+ break;
1786
+ case ALIGN_ITEMS_BASELINE:
1787
+ if (flexWrap != FLEX_WRAP_WRAP_REVERSE) {
1788
+ int marginTop = flexLine.mMaxBaseline - view.getBaseline();
1789
+ marginTop = Math.max(marginTop, lp.topMargin);
1790
+ view.layout(left, top + marginTop, right, bottom + marginTop);
1791
+ } else {
1792
+ int marginBottom = flexLine.mMaxBaseline - view.getMeasuredHeight() + view
1793
+ .getBaseline();
1794
+ marginBottom = Math.max(marginBottom, lp.bottomMargin);
1795
+ view.layout(left, top - marginBottom, right, bottom - marginBottom);
1796
+ }
1797
+ break;
1798
+ case ALIGN_ITEMS_FLEX_END:
1799
+ if (flexWrap != FLEX_WRAP_WRAP_REVERSE) {
1800
+ view.layout(left,
1801
+ top + crossSize - view.getMeasuredHeight() - lp.bottomMargin,
1802
+ right, top + crossSize - lp.bottomMargin);
1803
+ } else {
1804
+ // If the flexWrap == FLEX_WRAP_WRAP_REVERSE, the direction of the
1805
+ // flexEnd is flipped (from top to bottom).
1806
+ view.layout(left, top - crossSize + view.getMeasuredHeight() + lp.topMargin,
1807
+ right, bottom - crossSize + view.getMeasuredHeight() + lp.topMargin);
1808
+ }
1809
+ break;
1810
+ case ALIGN_ITEMS_CENTER:
1811
+ int topFromCrossAxis = (crossSize - view.getMeasuredHeight()) / 2;
1812
+ if (flexWrap != FLEX_WRAP_WRAP_REVERSE) {
1813
+ view.layout(left, top + topFromCrossAxis + lp.topMargin - lp.bottomMargin,
1814
+ right, top + topFromCrossAxis + view.getMeasuredHeight() + lp.topMargin
1815
+ - lp.bottomMargin);
1816
+ } else {
1817
+ view.layout(left, top - topFromCrossAxis + lp.topMargin - lp.bottomMargin,
1818
+ right, top - topFromCrossAxis + view.getMeasuredHeight() + lp.topMargin
1819
+ - lp.bottomMargin);
1820
+ }
1821
+ break;
1822
+ }
1823
+ }
1824
+
1825
+ /**
1826
+ * Sub method for {@link #onLayout(boolean, int, int, int, int)} when the
1827
+ * {@link #mFlexDirection} is either {@link #FLEX_DIRECTION_COLUMN} or
1828
+ * {@link #FLEX_DIRECTION_COLUMN_REVERSE}.
1829
+ *
1830
+ * @param isRtl {@code true} if the horizontal layout direction is right to left,
1831
+ * {@code false}
1832
+ * otherwise
1833
+ * @param fromBottomToTop {@code true} if the layout direction is bottom to top, {@code false}
1834
+ * otherwise
1835
+ * @param left the left position of this View
1836
+ * @param top the top position of this View
1837
+ * @param right the right position of this View
1838
+ * @param bottom the bottom position of this View
1839
+ * @see #getFlexWrap()
1840
+ * @see #setFlexWrap(int)
1841
+ * @see #getJustifyContent()
1842
+ * @see #setJustifyContent(int)
1843
+ * @see #getAlignItems()
1844
+ * @see #setAlignItems(int)
1845
+ * @see LayoutParams#alignSelf
1846
+ */
1847
+ private void layoutVertical(boolean isRtl, boolean fromBottomToTop, int left, int top,
1848
+ int right, int bottom) {
1849
+ int paddingTop = getPaddingTop();
1850
+ int paddingBottom = getPaddingBottom();
1851
+
1852
+ int paddingRight = getPaddingRight();
1853
+ int childLeft = getPaddingLeft();
1854
+ int currentViewIndex = 0;
1855
+
1856
+ int width = right - left;
1857
+ int height = bottom - top;
1858
+ // childRight is used if the mFlexWrap is FLEX_WRAP_WRAP_REVERSE otherwise
1859
+ // childLeft is used to align the horizontal position of the children views.
1860
+ int childRight = width - paddingRight;
1861
+
1862
+ // Use float to reduce the round error that may happen in when justifyContent ==
1863
+ // SPACE_BETWEEN or SPACE_AROUND
1864
+ float childTop;
1865
+
1866
+ // Used only for if the direction is from bottom to top
1867
+ float childBottom;
1868
+
1869
+ for (int i = 0, size = mFlexLines.size(); i < size; i++) {
1870
+ FlexLine flexLine = mFlexLines.get(i);
1871
+ if (hasDividerBeforeFlexLine(i)) {
1872
+ childLeft += mDividerVerticalWidth;
1873
+ childRight -= mDividerVerticalWidth;
1874
+ }
1875
+ float spaceBetweenItem = 0f;
1876
+ switch (mJustifyContent) {
1877
+ case JUSTIFY_CONTENT_FLEX_START:
1878
+ childTop = paddingTop;
1879
+ childBottom = height - paddingBottom;
1880
+ break;
1881
+ case JUSTIFY_CONTENT_FLEX_END:
1882
+ childTop = height - flexLine.mMainSize + paddingBottom;
1883
+ childBottom = flexLine.mMainSize - paddingTop;
1884
+ break;
1885
+ case JUSTIFY_CONTENT_CENTER:
1886
+ childTop = paddingTop + (height - flexLine.mMainSize) / 2f;
1887
+ childBottom = height - paddingBottom - (height - flexLine.mMainSize) / 2f;
1888
+ break;
1889
+ case JUSTIFY_CONTENT_SPACE_AROUND: {
1890
+ int visibleCount = flexLine.getLayoutVisibleItemCount();
1891
+ if (visibleCount != 0) {
1892
+ spaceBetweenItem = (height - flexLine.mMainSize)
1893
+ / (float) visibleCount;
1894
+ }
1895
+ childTop = paddingTop + spaceBetweenItem / 2f;
1896
+ childBottom = height - paddingBottom - spaceBetweenItem / 2f;
1897
+ break;
1898
+ }
1899
+ case JUSTIFY_CONTENT_SPACE_BETWEEN: {
1900
+ int visibleCount = flexLine.getLayoutVisibleItemCount();
1901
+ float denominator = visibleCount != 1 ? visibleCount - 1 : 1f;
1902
+
1903
+ childTop = paddingTop;
1904
+ spaceBetweenItem = (height - flexLine.mMainSize) / denominator;
1905
+ childBottom = height - paddingBottom;
1906
+ break;
1907
+ }
1908
+ default:
1909
+ throw new IllegalStateException(
1910
+ "Invalid justifyContent is set: " + mJustifyContent);
1911
+ }
1912
+ spaceBetweenItem = Math.max(spaceBetweenItem, 0);
1913
+
1914
+ for (int j = 0; j < flexLine.mItemCount; j++) {
1915
+ View child = getReorderedChildAt(currentViewIndex);
1916
+ if (child == null) {
1917
+ continue;
1918
+ } else if (child.getVisibility() == View.GONE) {
1919
+ currentViewIndex++;
1920
+ continue;
1921
+ }
1922
+ LayoutParams lp = ((LayoutParams) child.getLayoutParams());
1923
+ childTop += lp.topMargin;
1924
+ childBottom -= lp.bottomMargin;
1925
+ if (hasDividerBeforeChildAtAlongMainAxis(currentViewIndex, j)) {
1926
+ childTop += mDividerHorizontalHeight;
1927
+ childBottom -= mDividerHorizontalHeight;
1928
+ }
1929
+ if (isRtl) {
1930
+ if (fromBottomToTop) {
1931
+ layoutSingleChildVertical(child, flexLine, true, mAlignItems,
1932
+ childRight - child.getMeasuredWidth(),
1933
+ Math.round(childBottom) - child.getMeasuredHeight(), childRight,
1934
+ Math.round(childBottom));
1935
+ } else {
1936
+ layoutSingleChildVertical(child, flexLine, true, mAlignItems,
1937
+ childRight - child.getMeasuredWidth(), Math.round(childTop),
1938
+ childRight, Math.round(childTop) + child.getMeasuredHeight());
1939
+ }
1940
+ } else {
1941
+ if (fromBottomToTop) {
1942
+ layoutSingleChildVertical(child, flexLine, false, mAlignItems,
1943
+ childLeft, Math.round(childBottom) - child.getMeasuredHeight(),
1944
+ childLeft + child.getMeasuredWidth(), Math.round(childBottom));
1945
+ } else {
1946
+ layoutSingleChildVertical(child, flexLine, false, mAlignItems,
1947
+ childLeft, Math.round(childTop),
1948
+ childLeft + child.getMeasuredWidth(),
1949
+ Math.round(childTop) + child.getMeasuredHeight());
1950
+ }
1951
+ }
1952
+ childTop += child.getMeasuredHeight() + spaceBetweenItem + lp.bottomMargin;
1953
+ childBottom -= child.getMeasuredHeight() + spaceBetweenItem + lp.topMargin;
1954
+ currentViewIndex++;
1955
+
1956
+ flexLine.mLeft = Math.min(flexLine.mLeft, child.getLeft() - lp.leftMargin);
1957
+ flexLine.mTop = Math.min(flexLine.mTop, child.getTop() - lp.topMargin);
1958
+ flexLine.mRight = Math.max(flexLine.mRight, child.getRight() + lp.rightMargin);
1959
+ flexLine.mBottom = Math.max(flexLine.mBottom, child.getBottom() + lp.bottomMargin);
1960
+ }
1961
+ childLeft += flexLine.mCrossSize;
1962
+ childRight -= flexLine.mCrossSize;
1963
+ }
1964
+ }
1965
+
1966
+ /**
1967
+ * Place a single View when the layout direction is vertical ({@link #mFlexDirection} is
1968
+ * either {@link #FLEX_DIRECTION_COLUMN} or {@link #FLEX_DIRECTION_COLUMN_REVERSE}).
1969
+ *
1970
+ * @param view the View to be placed
1971
+ * @param flexLine the {@link FlexLine} where the View belongs to
1972
+ * @param isRtl {@code true} if the layout direction is right to left, {@code false}
1973
+ * otherwise
1974
+ * @param alignItems the align items attribute of this FlexboxLayout
1975
+ * @param left the left position of the flex line where the View belongs to. The actual
1976
+ * View's left position is shifted depending on the isRtl and alignItems
1977
+ * attributes
1978
+ * @param top the top position of the View, which the View's margin is already taken
1979
+ * into account
1980
+ * @param right the right position of the flex line where the View belongs to. The actual
1981
+ * View's right position is shifted depending on the isRtl and alignItems
1982
+ * attributes
1983
+ * @param bottom the bottom position of the View, which the View's margin is already taken
1984
+ * into account
1985
+ * @see #getAlignItems()
1986
+ * @see #setAlignItems(int)
1987
+ * @see LayoutParams#alignSelf
1988
+ */
1989
+ private void layoutSingleChildVertical(View view, FlexLine flexLine, boolean isRtl,
1990
+ int alignItems, int left, int top, int right, int bottom) {
1991
+ LayoutParams lp = (LayoutParams) view.getLayoutParams();
1992
+ if (lp.alignSelf != LayoutParams.ALIGN_SELF_AUTO) {
1993
+ // Expecting the values for alignItems and alignSelf match except for ALIGN_SELF_AUTO.
1994
+ // Assigning the alignSelf value as alignItems should work.
1995
+ alignItems = lp.alignSelf;
1996
+ }
1997
+ int crossSize = flexLine.mCrossSize;
1998
+ switch (alignItems) {
1999
+ case ALIGN_ITEMS_FLEX_START: // Intentional fall through
2000
+ case ALIGN_ITEMS_STRETCH: // Intentional fall through
2001
+ case ALIGN_ITEMS_BASELINE:
2002
+ if (!isRtl) {
2003
+ view.layout(left + lp.leftMargin, top, right + lp.leftMargin, bottom);
2004
+ } else {
2005
+ view.layout(left - lp.rightMargin, top, right - lp.rightMargin, bottom);
2006
+ }
2007
+ break;
2008
+ case ALIGN_ITEMS_FLEX_END:
2009
+ if (!isRtl) {
2010
+ view.layout(left + crossSize - view.getMeasuredWidth() - lp.rightMargin,
2011
+ top, right + crossSize - view.getMeasuredWidth() - lp.rightMargin,
2012
+ bottom);
2013
+ } else {
2014
+ // If the flexWrap == FLEX_WRAP_WRAP_REVERSE, the direction of the
2015
+ // flexEnd is flipped (from left to right).
2016
+ view.layout(left - crossSize + view.getMeasuredWidth() + lp.leftMargin, top,
2017
+ right - crossSize + view.getMeasuredWidth() + lp.leftMargin,
2018
+ bottom);
2019
+ }
2020
+ break;
2021
+ case ALIGN_ITEMS_CENTER:
2022
+ int leftFromCrossAxis = (crossSize - view.getMeasuredWidth()) / 2;
2023
+ if (!isRtl) {
2024
+ view.layout(left + leftFromCrossAxis + lp.leftMargin - lp.rightMargin,
2025
+ top, right + leftFromCrossAxis + lp.leftMargin - lp.rightMargin,
2026
+ bottom);
2027
+ } else {
2028
+ view.layout(left - leftFromCrossAxis + lp.leftMargin - lp.rightMargin,
2029
+ top, right - leftFromCrossAxis + lp.leftMargin - lp.rightMargin,
2030
+ bottom);
2031
+ }
2032
+ break;
2033
+ }
2034
+ }
2035
+
2036
+ @Override
2037
+ protected void onDraw(Canvas canvas) {
2038
+ if (mDividerDrawableVertical == null && mDividerDrawableHorizontal == null) {
2039
+ return;
2040
+ }
2041
+ if (mShowDividerHorizontal == SHOW_DIVIDER_NONE
2042
+ && mShowDividerVertical == SHOW_DIVIDER_NONE) {
2043
+ return;
2044
+ }
2045
+
2046
+ int layoutDirection = ViewCompat.getLayoutDirection(this);
2047
+ boolean isRtl;
2048
+ boolean fromBottomToTop = false;
2049
+ switch (mFlexDirection) {
2050
+ case FLEX_DIRECTION_ROW:
2051
+ isRtl = layoutDirection == ViewCompat.LAYOUT_DIRECTION_RTL;
2052
+ if (mFlexWrap == FLEX_WRAP_WRAP_REVERSE) {
2053
+ fromBottomToTop = true;
2054
+ }
2055
+ drawDividersHorizontal(canvas, isRtl, fromBottomToTop);
2056
+ break;
2057
+ case FLEX_DIRECTION_ROW_REVERSE:
2058
+ isRtl = layoutDirection != ViewCompat.LAYOUT_DIRECTION_RTL;
2059
+ if (mFlexWrap == FLEX_WRAP_WRAP_REVERSE) {
2060
+ fromBottomToTop = true;
2061
+ }
2062
+ drawDividersHorizontal(canvas, isRtl, fromBottomToTop);
2063
+ break;
2064
+ case FLEX_DIRECTION_COLUMN:
2065
+ isRtl = layoutDirection == ViewCompat.LAYOUT_DIRECTION_RTL;
2066
+ if (mFlexWrap == FLEX_WRAP_WRAP_REVERSE) {
2067
+ isRtl = !isRtl;
2068
+ }
2069
+ drawDividersVertical(canvas, isRtl, false /* fromBottomToTop */);
2070
+ break;
2071
+ case FLEX_DIRECTION_COLUMN_REVERSE:
2072
+ isRtl = layoutDirection == ViewCompat.LAYOUT_DIRECTION_RTL;
2073
+ if (mFlexWrap == FLEX_WRAP_WRAP_REVERSE) {
2074
+ isRtl = !isRtl;
2075
+ }
2076
+ drawDividersVertical(canvas, isRtl, true /* fromBottomToTop */);
2077
+ break;
2078
+ }
2079
+ }
2080
+
2081
+ /**
2082
+ * Sub method for {@link #onDraw(Canvas)} when the main axis direction is horizontal
2083
+ * ({@link #mFlexDirection} is either of {@link #FLEX_DIRECTION_ROW} or
2084
+ * {@link #FLEX_DIRECTION_ROW_REVERSE}.
2085
+ *
2086
+ * @param canvas the canvas on which the background will be drawn
2087
+ * @param isRtl {@code true} when the horizontal layout direction is right to left,
2088
+ * {@code false} otherwise
2089
+ * @param fromBottomToTop {@code true} when the vertical layout direction is bottom to top,
2090
+ * {@code false} otherwise
2091
+ */
2092
+ private void drawDividersHorizontal(Canvas canvas, boolean isRtl, boolean fromBottomToTop) {
2093
+ int currentViewIndex = 0;
2094
+ int paddingLeft = getPaddingLeft();
2095
+ int paddingRight = getPaddingRight();
2096
+ int horizontalDividerLength = Math.max(0, getWidth() - paddingRight - paddingLeft);
2097
+ for (int i = 0, size = mFlexLines.size(); i < size; i++) {
2098
+ FlexLine flexLine = mFlexLines.get(i);
2099
+ for (int j = 0; j < flexLine.mItemCount; j++) {
2100
+ View view = getReorderedChildAt(currentViewIndex);
2101
+
2102
+ if (view == null || view.getVisibility() == View.GONE) {
2103
+ continue;
2104
+ }
2105
+
2106
+ LayoutParams lp = (LayoutParams) view.getLayoutParams();
2107
+
2108
+ // Judge if the beginning or middle divider is needed
2109
+ if (hasDividerBeforeChildAtAlongMainAxis(currentViewIndex, j)) {
2110
+ int dividerLeft;
2111
+ if (isRtl) {
2112
+ dividerLeft = view.getRight() + lp.rightMargin;
2113
+ } else {
2114
+ dividerLeft = view.getLeft() - lp.leftMargin - mDividerVerticalWidth;
2115
+ }
2116
+
2117
+ drawVerticalDivider(canvas, dividerLeft, flexLine.mTop, flexLine.mCrossSize);
2118
+ }
2119
+
2120
+ // Judge if the end divider is needed
2121
+ if (j == flexLine.mItemCount - 1) {
2122
+ if ((mShowDividerVertical & SHOW_DIVIDER_END) > 0) {
2123
+ int dividerLeft;
2124
+ if (isRtl) {
2125
+ dividerLeft = view.getLeft() - lp.leftMargin - mDividerVerticalWidth;
2126
+ } else {
2127
+ dividerLeft = view.getRight() + lp.rightMargin;
2128
+ }
2129
+
2130
+ drawVerticalDivider(canvas, dividerLeft, flexLine.mTop,
2131
+ flexLine.mCrossSize);
2132
+ }
2133
+ }
2134
+ currentViewIndex++;
2135
+ }
2136
+
2137
+ // Judge if the beginning or middle dividers are needed before the flex line
2138
+ if (hasDividerBeforeFlexLine(i)) {
2139
+ int horizontalDividerTop;
2140
+ if (fromBottomToTop) {
2141
+ horizontalDividerTop = flexLine.mBottom;
2142
+ } else {
2143
+ horizontalDividerTop = flexLine.mTop - mDividerHorizontalHeight;
2144
+ }
2145
+ drawHorizontalDivider(canvas, paddingLeft, horizontalDividerTop,
2146
+ horizontalDividerLength);
2147
+ }
2148
+ // Judge if the end divider is needed before the flex line
2149
+ if (hasEndDividerAfterFlexLine(i)) {
2150
+ if ((mShowDividerHorizontal & SHOW_DIVIDER_END) > 0) {
2151
+ int horizontalDividerTop;
2152
+ if (fromBottomToTop) {
2153
+ horizontalDividerTop = flexLine.mTop - mDividerHorizontalHeight;
2154
+ } else {
2155
+ horizontalDividerTop = flexLine.mBottom;
2156
+ }
2157
+ drawHorizontalDivider(canvas, paddingLeft, horizontalDividerTop,
2158
+ horizontalDividerLength);
2159
+ }
2160
+ }
2161
+ }
2162
+ }
2163
+
2164
+ /**
2165
+ * Sub method for {@link #onDraw(Canvas)} when the main axis direction is vertical
2166
+ * ({@link #mFlexDirection} is either of {@link #FLEX_DIRECTION_COLUMN} or
2167
+ * {@link #FLEX_DIRECTION_COLUMN_REVERSE}.
2168
+ *
2169
+ * @param canvas the canvas on which the background will be drawn
2170
+ * @param isRtl {@code true} when the horizontal layout direction is right to left,
2171
+ * {@code false} otherwise
2172
+ * @param fromBottomToTop {@code true} when the vertical layout direction is bottom to top,
2173
+ * {@code false} otherwise
2174
+ */
2175
+ private void drawDividersVertical(Canvas canvas, boolean isRtl, boolean fromBottomToTop) {
2176
+ int currentViewIndex = 0;
2177
+ int paddingTop = getPaddingTop();
2178
+ int paddingBottom = getPaddingBottom();
2179
+ int verticalDividerLength = Math.max(0, getHeight() - paddingBottom - paddingTop);
2180
+ for (int i = 0, size = mFlexLines.size(); i < size; i++) {
2181
+ FlexLine flexLine = mFlexLines.get(i);
2182
+
2183
+ // Draw horizontal dividers if needed
2184
+ for (int j = 0; j < flexLine.mItemCount; j++) {
2185
+ View view = getReorderedChildAt(currentViewIndex);
2186
+
2187
+ if (view == null || view.getVisibility() == View.GONE) {
2188
+ continue;
2189
+ }
2190
+
2191
+ LayoutParams lp = (LayoutParams) view.getLayoutParams();
2192
+
2193
+ // Judge if the beginning or middle divider is needed
2194
+ if (hasDividerBeforeChildAtAlongMainAxis(currentViewIndex, j)) {
2195
+ int dividerTop;
2196
+ if (fromBottomToTop) {
2197
+ dividerTop = view.getBottom() + lp.bottomMargin;
2198
+ } else {
2199
+ dividerTop = view.getTop() - lp.topMargin - mDividerHorizontalHeight;
2200
+ }
2201
+
2202
+ drawHorizontalDivider(canvas, flexLine.mLeft, dividerTop, flexLine.mCrossSize);
2203
+ }
2204
+
2205
+ // Judge if the end divider is needed
2206
+ if (j == flexLine.mItemCount - 1) {
2207
+ if ((mShowDividerHorizontal & SHOW_DIVIDER_END) > 0) {
2208
+ int dividerTop;
2209
+ if (fromBottomToTop) {
2210
+ dividerTop = view.getTop() - lp.topMargin - mDividerHorizontalHeight;
2211
+ } else {
2212
+ dividerTop = view.getBottom() + lp.bottomMargin;
2213
+ }
2214
+
2215
+ drawHorizontalDivider(canvas, flexLine.mLeft, dividerTop,
2216
+ flexLine.mCrossSize);
2217
+ }
2218
+ }
2219
+ currentViewIndex++;
2220
+ }
2221
+
2222
+ // Judge if the beginning or middle dividers are needed before the flex line
2223
+ if (hasDividerBeforeFlexLine(i)) {
2224
+ int verticalDividerLeft;
2225
+ if (isRtl) {
2226
+ verticalDividerLeft = flexLine.mRight;
2227
+ } else {
2228
+ verticalDividerLeft = flexLine.mLeft - mDividerVerticalWidth;
2229
+ }
2230
+ drawVerticalDivider(canvas, verticalDividerLeft, paddingTop,
2231
+ verticalDividerLength);
2232
+ }
2233
+ if (hasEndDividerAfterFlexLine(i)) {
2234
+ if ((mShowDividerVertical & SHOW_DIVIDER_END) > 0) {
2235
+ int verticalDividerLeft;
2236
+ if (isRtl) {
2237
+ verticalDividerLeft = flexLine.mLeft - mDividerVerticalWidth;
2238
+ } else {
2239
+ verticalDividerLeft = flexLine.mRight;
2240
+ }
2241
+ drawVerticalDivider(canvas, verticalDividerLeft, paddingTop,
2242
+ verticalDividerLength);
2243
+ }
2244
+ }
2245
+ }
2246
+ }
2247
+
2248
+ private void drawVerticalDivider(Canvas canvas, int left, int top, int length) {
2249
+ if (mDividerDrawableVertical == null) {
2250
+ return;
2251
+ }
2252
+ mDividerDrawableVertical.setBounds(left, top, left + mDividerVerticalWidth, top + length);
2253
+ mDividerDrawableVertical.draw(canvas);
2254
+ }
2255
+
2256
+ private void drawHorizontalDivider(Canvas canvas, int left, int top, int length) {
2257
+ if (mDividerDrawableHorizontal == null) {
2258
+ return;
2259
+ }
2260
+ mDividerDrawableHorizontal
2261
+ .setBounds(left, top, left + length, top + mDividerHorizontalHeight);
2262
+ mDividerDrawableHorizontal.draw(canvas);
2263
+ }
2264
+
2265
+ @Override
2266
+ protected LayoutParams generateDefaultLayoutParams() {
2267
+ return new FlexboxLayout.LayoutParams();
2268
+ }
2269
+
2270
+ @Override
2271
+ protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
2272
+ return p instanceof FlexboxLayout.LayoutParams;
2273
+ }
2274
+
2275
+ @Override
2276
+ public LayoutParams generateLayoutParams(AttributeSet attrs) {
2277
+ return new FlexboxLayout.LayoutParams();
2278
+ }
2279
+
2280
+ @Override
2281
+ protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams from) {
2282
+ if (from instanceof FlexboxLayout.LayoutParams)
2283
+ return new FlexboxLayout.LayoutParams((FlexboxLayout.LayoutParams) from);
2284
+
2285
+ if (from instanceof CommonLayoutParams)
2286
+ return new FlexboxLayout.LayoutParams((CommonLayoutParams) from);
2287
+
2288
+ if (from instanceof FrameLayout.LayoutParams)
2289
+ return new FlexboxLayout.LayoutParams((FrameLayout.LayoutParams) from);
2290
+
2291
+ if (from instanceof ViewGroup.MarginLayoutParams)
2292
+ return new FlexboxLayout.LayoutParams((ViewGroup.MarginLayoutParams) from);
2293
+
2294
+ return new FlexboxLayout.LayoutParams(from);
2295
+ }
2296
+
2297
+ @FlexDirection
2298
+ public int getFlexDirection() {
2299
+ return mFlexDirection;
2300
+ }
2301
+
2302
+ public void setFlexDirection(@FlexDirection int flexDirection) {
2303
+ if (mFlexDirection != flexDirection) {
2304
+ mFlexDirection = flexDirection;
2305
+ requestLayout();
2306
+ }
2307
+ }
2308
+
2309
+ @FlexWrap
2310
+ public int getFlexWrap() {
2311
+ return mFlexWrap;
2312
+ }
2313
+
2314
+ public void setFlexWrap(@FlexWrap int flexWrap) {
2315
+ if (mFlexWrap != flexWrap) {
2316
+ mFlexWrap = flexWrap;
2317
+ requestLayout();
2318
+ }
2319
+ }
2320
+
2321
+ @JustifyContent
2322
+ public int getJustifyContent() {
2323
+ return mJustifyContent;
2324
+ }
2325
+
2326
+ public void setJustifyContent(@JustifyContent int justifyContent) {
2327
+ if (mJustifyContent != justifyContent) {
2328
+ mJustifyContent = justifyContent;
2329
+ requestLayout();
2330
+ }
2331
+ }
2332
+
2333
+ @AlignItems
2334
+ public int getAlignItems() {
2335
+ return mAlignItems;
2336
+ }
2337
+
2338
+ public void setAlignItems(@AlignItems int alignItems) {
2339
+ if (mAlignItems != alignItems) {
2340
+ mAlignItems = alignItems;
2341
+ requestLayout();
2342
+ }
2343
+ }
2344
+
2345
+ @AlignContent
2346
+ public int getAlignContent() {
2347
+ return mAlignContent;
2348
+ }
2349
+
2350
+ public void setAlignContent(@AlignContent int alignContent) {
2351
+ if (mAlignContent != alignContent) {
2352
+ mAlignContent = alignContent;
2353
+ requestLayout();
2354
+ }
2355
+ }
2356
+
2357
+ /**
2358
+ * @return the flex lines composing this flex container. This method returns a copy of the
2359
+ * original list excluding a dummy flex line (flex line that doesn't have any flex items in it
2360
+ * but used for the alignment along the cross axis).
2361
+ * Thus any changes of the returned list are not reflected to the original list.
2362
+ */
2363
+ public List<FlexLine> getFlexLines() {
2364
+ List<FlexLine> result = new ArrayList<>(mFlexLines.size());
2365
+ for (FlexLine flexLine : mFlexLines) {
2366
+ if (flexLine.getLayoutVisibleItemCount() == 0) {
2367
+ continue;
2368
+ }
2369
+ result.add(flexLine);
2370
+ }
2371
+ return result;
2372
+ }
2373
+
2374
+ /**
2375
+ * @return the horizontal divider drawable that will divide each item.
2376
+ * @see #setDividerDrawable(Drawable)
2377
+ * @see #setDividerDrawableHorizontal(Drawable)
2378
+ */
2379
+ public Drawable getDividerDrawableHorizontal() {
2380
+ return mDividerDrawableHorizontal;
2381
+ }
2382
+
2383
+ /**
2384
+ * @return the vertical divider drawable that will divide each item.
2385
+ * @see #setDividerDrawable(Drawable)
2386
+ * @see #setDividerDrawableVertical(Drawable)
2387
+ */
2388
+ public Drawable getDividerDrawableVertical() {
2389
+ return mDividerDrawableVertical;
2390
+ }
2391
+
2392
+ /**
2393
+ * Set a drawable to be used as a divider between items. The drawable is used for both
2394
+ * horizontal and vertical dividers.
2395
+ *
2396
+ * @param divider Drawable that will divide each item for both horizontally and vertically.
2397
+ * @see #setShowDivider(int)
2398
+ */
2399
+ public void setDividerDrawable(Drawable divider) {
2400
+ setDividerDrawableHorizontal(divider);
2401
+ setDividerDrawableVertical(divider);
2402
+ }
2403
+
2404
+ /**
2405
+ * Set a drawable to be used as a horizontal divider between items.
2406
+ *
2407
+ * @param divider Drawable that will divide each item.
2408
+ * @see #setDividerDrawable(Drawable)
2409
+ * @see #setShowDivider(int)
2410
+ * @see #setShowDividerHorizontal(int)
2411
+ */
2412
+ public void setDividerDrawableHorizontal(Drawable divider) {
2413
+ if (divider == mDividerDrawableHorizontal) {
2414
+ return;
2415
+ }
2416
+ mDividerDrawableHorizontal = divider;
2417
+ if (divider != null) {
2418
+ mDividerHorizontalHeight = divider.getIntrinsicHeight();
2419
+ } else {
2420
+ mDividerHorizontalHeight = 0;
2421
+ }
2422
+ setWillNotDrawFlag();
2423
+ requestLayout();
2424
+ }
2425
+
2426
+ /**
2427
+ * Set a drawable to be used as a vertical divider between items.
2428
+ *
2429
+ * @param divider Drawable that will divide each item.
2430
+ * @see #setDividerDrawable(Drawable)
2431
+ * @see #setShowDivider(int)
2432
+ * @see #setShowDividerVertical(int)
2433
+ */
2434
+ public void setDividerDrawableVertical(Drawable divider) {
2435
+ if (divider == mDividerDrawableVertical) {
2436
+ return;
2437
+ }
2438
+ mDividerDrawableVertical = divider;
2439
+ if (divider != null) {
2440
+ mDividerVerticalWidth = divider.getIntrinsicWidth();
2441
+ } else {
2442
+ mDividerVerticalWidth = 0;
2443
+ }
2444
+ setWillNotDrawFlag();
2445
+ requestLayout();
2446
+ }
2447
+
2448
+ @FlexboxLayout.DividerMode
2449
+ public int getShowDividerVertical() {
2450
+ return mShowDividerVertical;
2451
+ }
2452
+
2453
+ @FlexboxLayout.DividerMode
2454
+ public int getShowDividerHorizontal() {
2455
+ return mShowDividerHorizontal;
2456
+ }
2457
+
2458
+ /**
2459
+ * Set how dividers should be shown between items in this layout. This method sets the
2460
+ * divider mode for both horizontally and vertically.
2461
+ *
2462
+ * @param dividerMode One or more of {@link #SHOW_DIVIDER_BEGINNING},
2463
+ * {@link #SHOW_DIVIDER_MIDDLE}, or {@link #SHOW_DIVIDER_END},
2464
+ * or {@link #SHOW_DIVIDER_NONE} to show no dividers.
2465
+ * @see #setShowDividerVertical(int)
2466
+ * @see #setShowDividerHorizontal(int)
2467
+ */
2468
+ public void setShowDivider(@DividerMode int dividerMode) {
2469
+ setShowDividerVertical(dividerMode);
2470
+ setShowDividerHorizontal(dividerMode);
2471
+ }
2472
+
2473
+ /**
2474
+ * Set how vertical dividers should be shown between items in this layout
2475
+ *
2476
+ * @param dividerMode One or more of {@link #SHOW_DIVIDER_BEGINNING},
2477
+ * {@link #SHOW_DIVIDER_MIDDLE}, or {@link #SHOW_DIVIDER_END},
2478
+ * or {@link #SHOW_DIVIDER_NONE} to show no dividers.
2479
+ * @see #setShowDivider(int)
2480
+ */
2481
+ public void setShowDividerVertical(@DividerMode int dividerMode) {
2482
+ if (dividerMode != mShowDividerVertical) {
2483
+ mShowDividerVertical = dividerMode;
2484
+ requestLayout();
2485
+ }
2486
+ }
2487
+
2488
+ /**
2489
+ * Set how horizontal dividers should be shown between items in this layout.
2490
+ *
2491
+ * @param dividerMode One or more of {@link #SHOW_DIVIDER_BEGINNING},
2492
+ * {@link #SHOW_DIVIDER_MIDDLE}, or {@link #SHOW_DIVIDER_END},
2493
+ * or {@link #SHOW_DIVIDER_NONE} to show no dividers.
2494
+ * @see #setShowDivider(int)
2495
+ */
2496
+ public void setShowDividerHorizontal(@DividerMode int dividerMode) {
2497
+ if (dividerMode != mShowDividerHorizontal) {
2498
+ mShowDividerHorizontal = dividerMode;
2499
+ requestLayout();
2500
+ }
2501
+ }
2502
+
2503
+ private void setWillNotDrawFlag() {
2504
+ setWillNotDraw(mDividerDrawableHorizontal == null && mDividerDrawableVertical == null);
2505
+ }
2506
+
2507
+ /**
2508
+ * Check if a divider is needed before the view whose indices are passed as arguments.
2509
+ *
2510
+ * @param childAbsoluteIndex the absolute index of the view to be judged
2511
+ * @param childRelativeIndexInFlexLine the relative index in the flex line where the view
2512
+ * belongs
2513
+ * @return {@code true} if a divider is needed, {@code false} otherwise
2514
+ */
2515
+ private boolean hasDividerBeforeChildAtAlongMainAxis(int childAbsoluteIndex,
2516
+ int childRelativeIndexInFlexLine) {
2517
+ if (allViewsAreGoneBefore(childAbsoluteIndex, childRelativeIndexInFlexLine)) {
2518
+ if (isMainAxisDirectionHorizontal(mFlexDirection)) {
2519
+ return (mShowDividerVertical & SHOW_DIVIDER_BEGINNING) != 0;
2520
+ } else {
2521
+ return (mShowDividerHorizontal & SHOW_DIVIDER_BEGINNING) != 0;
2522
+ }
2523
+ } else {
2524
+ if (isMainAxisDirectionHorizontal(mFlexDirection)) {
2525
+ return (mShowDividerVertical & SHOW_DIVIDER_MIDDLE) != 0;
2526
+ } else {
2527
+ return (mShowDividerHorizontal & SHOW_DIVIDER_MIDDLE) != 0;
2528
+ }
2529
+ }
2530
+ }
2531
+
2532
+ private boolean allViewsAreGoneBefore(int childAbsoluteIndex,
2533
+ int childRelativeIndexInFlexLine) {
2534
+ for (int i = 1; i <= childRelativeIndexInFlexLine; i++) {
2535
+ View view = getReorderedChildAt(childAbsoluteIndex - i);
2536
+ if (view != null && view.getVisibility() != View.GONE) {
2537
+ return false;
2538
+ }
2539
+ }
2540
+ return true;
2541
+ }
2542
+
2543
+ /**
2544
+ * Check if a divider is needed before the flex line whose index is passed as an argument.
2545
+ *
2546
+ * @param flexLineIndex the index of the flex line to be checked
2547
+ * @return {@code true} if a divider is needed, {@code false} otherwise
2548
+ */
2549
+ private boolean hasDividerBeforeFlexLine(int flexLineIndex) {
2550
+ if (flexLineIndex < 0 || flexLineIndex >= mFlexLines.size()) {
2551
+ return false;
2552
+ }
2553
+ if (allFlexLinesAreDummyBefore(flexLineIndex)) {
2554
+ if (isMainAxisDirectionHorizontal(mFlexDirection)) {
2555
+ return (mShowDividerHorizontal & SHOW_DIVIDER_BEGINNING) != 0;
2556
+ } else {
2557
+ return (mShowDividerVertical & SHOW_DIVIDER_BEGINNING) != 0;
2558
+ }
2559
+ } else {
2560
+ if (isMainAxisDirectionHorizontal(mFlexDirection)) {
2561
+ return (mShowDividerHorizontal & SHOW_DIVIDER_MIDDLE) != 0;
2562
+ } else {
2563
+ return (mShowDividerVertical & SHOW_DIVIDER_MIDDLE) != 0;
2564
+ }
2565
+ }
2566
+ }
2567
+
2568
+ private boolean allFlexLinesAreDummyBefore(int flexLineIndex) {
2569
+ for (int i = 0; i < flexLineIndex; i++) {
2570
+ if (mFlexLines.get(i).getLayoutVisibleItemCount() > 0) {
2571
+ return false;
2572
+ }
2573
+ }
2574
+ return true;
2575
+ }
2576
+
2577
+ /**
2578
+ * Check if a end divider is needed after the flex line whose index is passed as an argument.
2579
+ *
2580
+ * @param flexLineIndex the index of the flex line to be checked
2581
+ * @return {@code true} if a divider is needed, {@code false} otherwise
2582
+ */
2583
+ private boolean hasEndDividerAfterFlexLine(int flexLineIndex) {
2584
+ if (flexLineIndex < 0 || flexLineIndex >= mFlexLines.size()) {
2585
+ return false;
2586
+ }
2587
+
2588
+ for (int i = flexLineIndex + 1; i < mFlexLines.size(); i++) {
2589
+ if (mFlexLines.get(i).getLayoutVisibleItemCount() > 0) {
2590
+ return false;
2591
+ }
2592
+ }
2593
+ if (isMainAxisDirectionHorizontal(mFlexDirection)) {
2594
+ return (mShowDividerHorizontal & SHOW_DIVIDER_END) != 0;
2595
+ } else {
2596
+ return (mShowDividerVertical & SHOW_DIVIDER_END) != 0;
2597
+ }
2598
+
2599
+ }
2600
+
2601
+ /**
2602
+ * Per child parameters for children views of the {@link FlexboxLayout}.
2603
+ */
2604
+ public static class LayoutParams extends CommonLayoutParams {
2605
+
2606
+ private static final int ORDER_DEFAULT = 1;
2607
+
2608
+ private static final float FLEX_GROW_DEFAULT = 0f;
2609
+
2610
+ private static final float FLEX_SHRINK_DEFAULT = 1f;
2611
+
2612
+ public static final float FLEX_BASIS_PERCENT_DEFAULT = -1f;
2613
+
2614
+ public static final int ALIGN_SELF_AUTO = -1;
2615
+
2616
+ public static final int ALIGN_SELF_FLEX_START = ALIGN_ITEMS_FLEX_START;
2617
+
2618
+ public static final int ALIGN_SELF_FLEX_END = ALIGN_ITEMS_FLEX_END;
2619
+
2620
+ public static final int ALIGN_SELF_CENTER = ALIGN_ITEMS_CENTER;
2621
+
2622
+ public static final int ALIGN_SELF_BASELINE = ALIGN_ITEMS_BASELINE;
2623
+
2624
+ public static final int ALIGN_SELF_STRETCH = ALIGN_ITEMS_STRETCH;
2625
+
2626
+ private static final int MAX_SIZE = Integer.MAX_VALUE & View.MEASURED_SIZE_MASK;
2627
+
2628
+ /**
2629
+ * This attribute can change the ordering of the children views are laid out.
2630
+ * By default, children are displayed and laid out in the same order as they appear in the
2631
+ * layout XML. If not specified, {@link #ORDER_DEFAULT} is set as a default value.
2632
+ */
2633
+ public int order = ORDER_DEFAULT;
2634
+
2635
+ /**
2636
+ * This attribute determines how much this child will grow if positive free space is
2637
+ * distributed relative to the rest of other flex items included in the same flex line.
2638
+ * If not specified, {@link #FLEX_GROW_DEFAULT} is set as a default value.
2639
+ */
2640
+ public float flexGrow = FLEX_GROW_DEFAULT;
2641
+
2642
+ /**
2643
+ * This attributes determines how much this child will shrink is negative free space is
2644
+ * distributed relative to the rest of other flex items included in the same flex line.
2645
+ * If not specified, {@link #FLEX_SHRINK_DEFAULT} is set as a default value.
2646
+ */
2647
+ public float flexShrink = FLEX_SHRINK_DEFAULT;
2648
+
2649
+ /**
2650
+ * This attributes determines the alignment along the cross axis (perpendicular to the
2651
+ * main axis). The alignment in the same direction can be determined by the
2652
+ * {@link #mAlignItems} in the parent, but if this is set to other than
2653
+ * {@link #ALIGN_SELF_AUTO}, the cross axis alignment is overridden for this child.
2654
+ * The value needs to be one of the values in ({@link #ALIGN_SELF_AUTO},
2655
+ * {@link #ALIGN_SELF_STRETCH}, {@link #ALIGN_SELF_FLEX_START}, {@link
2656
+ * #ALIGN_SELF_FLEX_END}, {@link #ALIGN_SELF_CENTER}, or {@link #ALIGN_SELF_BASELINE}).
2657
+ * If not specified, {@link #ALIGN_SELF_AUTO} is set as a default value.
2658
+ */
2659
+ public int alignSelf = ALIGN_SELF_AUTO;
2660
+
2661
+ /**
2662
+ * The initial flex item length in a fraction format relative to its parent.
2663
+ * The initial main size of this child View is trying to be expanded as the specified
2664
+ * fraction against the parent main size.
2665
+ * If this value is set, the length specified from layout_width
2666
+ * (or layout_height) is overridden by the calculated value from this attribute.
2667
+ * This attribute is only effective when the parent's MeasureSpec mode is
2668
+ * MeasureSpec.EXACTLY. The default value is {@link #FLEX_BASIS_PERCENT_DEFAULT}, which
2669
+ * means not set.
2670
+ */
2671
+ public float flexBasisPercent = FLEX_BASIS_PERCENT_DEFAULT;
2672
+
2673
+ /**
2674
+ * This attribute determines the minimum width the child can shrink to.
2675
+ */
2676
+ public int minWidth;
2677
+
2678
+ /**
2679
+ * This attribute determines the minimum height the child can shrink to.
2680
+ */
2681
+ public int minHeight;
2682
+
2683
+ /**
2684
+ * This attribute determines the maximum width the child can expand to.
2685
+ */
2686
+ public int maxWidth = MAX_SIZE;
2687
+
2688
+ /**
2689
+ * This attribute determines the maximum height the child can expand to.
2690
+ */
2691
+ public int maxHeight = MAX_SIZE;
2692
+
2693
+ /**
2694
+ * This attribute forces a flex line wrapping. i.e. if this is set to {@code true} for a
2695
+ * flex item, the item will become the first item of the new flex line. (A wrapping happens
2696
+ * regardless of the flex items being processed in the the previous flex line)
2697
+ * This attribute is ignored if the flex_wrap attribute is set as nowrap.
2698
+ * The equivalent attribute isn't defined in the original CSS Flexible Box Module
2699
+ * specification, but having this attribute is useful for Android developers to flatten
2700
+ * the layouts when building a grid like layout or for a situation where developers want
2701
+ * to put a new flex line to make a semantic difference from the previous one, etc.
2702
+ */
2703
+ public boolean wrapBefore;
2704
+
2705
+ public LayoutParams() {
2706
+ super();
2707
+ }
2708
+
2709
+ public LayoutParams(ViewGroup.LayoutParams source) {
2710
+ super(source);
2711
+ }
2712
+
2713
+ public LayoutParams(ViewGroup.MarginLayoutParams source) {
2714
+ super(source);
2715
+ }
2716
+
2717
+ public LayoutParams(FrameLayout.LayoutParams source) {
2718
+ super(source);
2719
+ }
2720
+
2721
+ public LayoutParams(CommonLayoutParams source) {
2722
+ super(source);
2723
+ }
2724
+
2725
+ public LayoutParams(LayoutParams source) {
2726
+ super(source);
2727
+
2728
+ this.order = source.order;
2729
+ this.flexGrow = source.flexGrow;
2730
+ this.flexShrink = source.flexShrink;
2731
+ this.wrapBefore = source.wrapBefore;
2732
+ this.alignSelf = source.alignSelf;
2733
+ }
2734
+ }
2735
+
2736
+ /**
2737
+ * A class that is used for calculating the view order which view's indices and order
2738
+ * properties from Flexbox are taken into account.
2739
+ */
2740
+ private static class Order implements Comparable<Order> {
2741
+
2742
+ /**
2743
+ * {@link View}'s index
2744
+ */
2745
+ int index;
2746
+
2747
+ /**
2748
+ * order property in the Flexbox
2749
+ */
2750
+ int order;
2751
+
2752
+ @Override
2753
+ public int compareTo(@NonNull Order another) {
2754
+ if (order != another.order) {
2755
+ return order - another.order;
2756
+ }
2757
+ return index - another.index;
2758
+ }
2759
+
2760
+ @NonNull
2761
+ @Override
2762
+ public String toString() {
2763
+ return "Order{" +
2764
+ "order=" + order +
2765
+ ", index=" + index +
2766
+ '}';
2767
+ }
2768
+ }
2769
+ }