|
19 | 19 | import com.google.android.material.R; |
20 | 20 |
|
21 | 21 | import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP; |
| 22 | +import static java.lang.Math.max; |
| 23 | +import static java.lang.Math.min; |
22 | 24 |
|
23 | 25 | import android.content.Context; |
24 | 26 | import android.content.res.Resources; |
|
31 | 33 | import androidx.annotation.RestrictTo; |
32 | 34 | import com.google.android.material.navigation.NavigationBarItemView; |
33 | 35 | import com.google.android.material.navigation.NavigationBarMenuView; |
| 36 | +import com.google.android.material.navigation.NavigationBarView; |
34 | 37 | import java.util.ArrayList; |
35 | 38 | import java.util.List; |
36 | 39 |
|
@@ -76,76 +79,101 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { |
76 | 79 | final int totalCount = getChildCount(); |
77 | 80 | tempChildWidths.clear(); |
78 | 81 |
|
| 82 | + int totalWidth = 0; |
| 83 | + int maxHeight = 0; |
| 84 | + |
79 | 85 | int parentHeight = MeasureSpec.getSize(heightMeasureSpec); |
80 | 86 | final int heightSpec = MeasureSpec.makeMeasureSpec(parentHeight, MeasureSpec.AT_MOST); |
81 | 87 |
|
82 | | - if (isShifting(getLabelVisibilityMode(), visibleCount) |
83 | | - && isItemHorizontalTranslationEnabled()) { |
84 | | - final View activeChild = getChildAt(getSelectedItemPosition()); |
85 | | - int activeItemWidth = activeItemMinWidth; |
86 | | - if (activeChild.getVisibility() != View.GONE) { |
87 | | - // Do an AT_MOST measure pass on the active child to get its desired width, and resize the |
88 | | - // active child view based on that width |
89 | | - activeChild.measure( |
90 | | - MeasureSpec.makeMeasureSpec(activeItemMaxWidth, MeasureSpec.AT_MOST), heightSpec); |
91 | | - activeItemWidth = Math.max(activeItemWidth, activeChild.getMeasuredWidth()); |
| 88 | + if (getItemIconGravity() == NavigationBarView.ITEM_ICON_GRAVITY_TOP) { |
| 89 | + if (isShifting(getLabelVisibilityMode(), visibleCount) |
| 90 | + && isItemHorizontalTranslationEnabled()) { |
| 91 | + final View activeChild = getChildAt(getSelectedItemPosition()); |
| 92 | + int activeItemWidth = activeItemMinWidth; |
| 93 | + if (activeChild.getVisibility() != View.GONE) { |
| 94 | + // Do an AT_MOST measure pass on the active child to get its desired width, and resize the |
| 95 | + // active child view based on that width |
| 96 | + activeChild.measure( |
| 97 | + MeasureSpec.makeMeasureSpec(activeItemMaxWidth, MeasureSpec.AT_MOST), heightSpec); |
| 98 | + activeItemWidth = max(activeItemWidth, activeChild.getMeasuredWidth()); |
| 99 | + } |
| 100 | + final int inactiveCount = visibleCount - (activeChild.getVisibility() != View.GONE ? 1 : 0); |
| 101 | + final int activeMaxAvailable = width - inactiveCount * inactiveItemMinWidth; |
| 102 | + final int activeWidth = min(activeMaxAvailable, min(activeItemWidth, activeItemMaxWidth)); |
| 103 | + final int inactiveMaxAvailable = |
| 104 | + (width - activeWidth) / (inactiveCount == 0 ? 1 : inactiveCount); |
| 105 | + final int inactiveWidth = min(inactiveMaxAvailable, inactiveItemMaxWidth); |
| 106 | + int extra = width - activeWidth - inactiveWidth * inactiveCount; |
| 107 | + |
| 108 | + for (int i = 0; i < totalCount; i++) { |
| 109 | + int tempChildWidth = 0; |
| 110 | + if (getChildAt(i).getVisibility() != View.GONE) { |
| 111 | + tempChildWidth = (i == getSelectedItemPosition()) ? activeWidth : inactiveWidth; |
| 112 | + // Account for integer division which sometimes leaves some extra pixel spaces. |
| 113 | + // e.g. If the nav was 10px wide, and 3 children were measured to be 3px-3px-3px, there |
| 114 | + // would be a 1px gap somewhere, which this fills in. |
| 115 | + if (extra > 0) { |
| 116 | + tempChildWidth++; |
| 117 | + extra--; |
| 118 | + } |
| 119 | + } |
| 120 | + tempChildWidths.add(tempChildWidth); |
| 121 | + } |
| 122 | + } else { |
| 123 | + final int maxAvailable = width / (visibleCount == 0 ? 1 : visibleCount); |
| 124 | + final int childWidth = min(maxAvailable, activeItemMaxWidth); |
| 125 | + int extra = width - childWidth * visibleCount; |
| 126 | + for (int i = 0; i < totalCount; i++) { |
| 127 | + int tempChildWidth = 0; |
| 128 | + if (getChildAt(i).getVisibility() != View.GONE) { |
| 129 | + tempChildWidth = childWidth; |
| 130 | + if (extra > 0) { |
| 131 | + tempChildWidth++; |
| 132 | + extra--; |
| 133 | + } |
| 134 | + } |
| 135 | + tempChildWidths.add(tempChildWidth); |
| 136 | + } |
92 | 137 | } |
93 | | - final int inactiveCount = visibleCount - (activeChild.getVisibility() != View.GONE ? 1 : 0); |
94 | | - final int activeMaxAvailable = width - inactiveCount * inactiveItemMinWidth; |
95 | | - final int activeWidth = |
96 | | - Math.min(activeMaxAvailable, Math.min(activeItemWidth, activeItemMaxWidth)); |
97 | | - final int inactiveMaxAvailable = |
98 | | - (width - activeWidth) / (inactiveCount == 0 ? 1 : inactiveCount); |
99 | | - final int inactiveWidth = Math.min(inactiveMaxAvailable, inactiveItemMaxWidth); |
100 | | - int extra = width - activeWidth - inactiveWidth * inactiveCount; |
101 | 138 |
|
102 | 139 | for (int i = 0; i < totalCount; i++) { |
103 | | - int tempChildWidth = 0; |
104 | | - if (getChildAt(i).getVisibility() != View.GONE) { |
105 | | - tempChildWidth = (i == getSelectedItemPosition()) ? activeWidth : inactiveWidth; |
106 | | - // Account for integer division which sometimes leaves some extra pixel spaces. |
107 | | - // e.g. If the nav was 10px wide, and 3 children were measured to be 3px-3px-3px, there |
108 | | - // would be a 1px gap somewhere, which this fills in. |
109 | | - if (extra > 0) { |
110 | | - tempChildWidth++; |
111 | | - extra--; |
112 | | - } |
| 140 | + final View child = getChildAt(i); |
| 141 | + if (child.getVisibility() == GONE) { |
| 142 | + continue; |
113 | 143 | } |
114 | | - tempChildWidths.add(tempChildWidth); |
| 144 | + child.measure( |
| 145 | + MeasureSpec.makeMeasureSpec(tempChildWidths.get(i), MeasureSpec.EXACTLY), heightSpec); |
| 146 | + ViewGroup.LayoutParams params = child.getLayoutParams(); |
| 147 | + params.width = child.getMeasuredWidth(); |
| 148 | + totalWidth += child.getMeasuredWidth(); |
| 149 | + maxHeight = max(maxHeight, child.getMeasuredHeight()); |
115 | 150 | } |
116 | | - } else { |
117 | | - final int maxAvailable = width / (visibleCount == 0 ? 1 : visibleCount); |
118 | | - final int childWidth = Math.min(maxAvailable, activeItemMaxWidth); |
119 | | - int extra = width - childWidth * visibleCount; |
| 151 | + } else { // icon gravity is start |
| 152 | + int childCount = visibleCount == 0 ? 1 : visibleCount; |
| 153 | + // Calculate the min nav item width based on the item count and bar width according to |
| 154 | + // these rules: |
| 155 | + // 3 items: the items should occupy 60% of the bar's width |
| 156 | + // 4 items: the items should occupy 70% of the bar's width |
| 157 | + // 5 items: the items should occupy 80% of the bar's width |
| 158 | + // 6+ items: the items should occupy 90% of the bar's width |
| 159 | + int minChildWidth = Math.round((min((childCount + 3) / 10f, 0.9f) * width) / childCount); |
| 160 | + int maxChildWidth = Math.round((float) width / childCount); |
120 | 161 | for (int i = 0; i < totalCount; i++) { |
121 | | - int tempChildWidth = 0; |
122 | | - if (getChildAt(i).getVisibility() != View.GONE) { |
123 | | - tempChildWidth = childWidth; |
124 | | - if (extra > 0) { |
125 | | - tempChildWidth++; |
126 | | - extra--; |
| 162 | + View child = getChildAt(i); |
| 163 | + if (child.getVisibility() != View.GONE) { |
| 164 | + child.measure( |
| 165 | + MeasureSpec.makeMeasureSpec(maxChildWidth, MeasureSpec.AT_MOST), heightSpec); |
| 166 | + if (child.getMeasuredWidth() < minChildWidth) { |
| 167 | + child.measure( |
| 168 | + MeasureSpec.makeMeasureSpec(minChildWidth, MeasureSpec.EXACTLY), heightSpec); |
| 169 | + } |
| 170 | + totalWidth += child.getMeasuredWidth(); |
| 171 | + maxHeight = max(maxHeight, child.getMeasuredHeight()); |
127 | 172 | } |
128 | 173 | } |
129 | | - tempChildWidths.add(tempChildWidth); |
130 | | - } |
131 | | - } |
132 | | - |
133 | | - int totalWidth = 0; |
134 | | - int maxHeight = 0; |
135 | | - for (int i = 0; i < totalCount; i++) { |
136 | | - final View child = getChildAt(i); |
137 | | - if (child.getVisibility() == GONE) { |
138 | | - continue; |
139 | | - } |
140 | | - child.measure( |
141 | | - MeasureSpec.makeMeasureSpec(tempChildWidths.get(i), MeasureSpec.EXACTLY), heightSpec); |
142 | | - ViewGroup.LayoutParams params = child.getLayoutParams(); |
143 | | - params.width = child.getMeasuredWidth(); |
144 | | - totalWidth += child.getMeasuredWidth(); |
145 | | - maxHeight = Math.max(maxHeight, child.getMeasuredHeight()); |
146 | 174 | } |
147 | 175 |
|
148 | | - setMeasuredDimension(totalWidth, Math.max(maxHeight, getSuggestedMinimumHeight())); |
| 176 | + setMeasuredDimension(totalWidth, max(maxHeight, getSuggestedMinimumHeight())); |
149 | 177 | } |
150 | 178 |
|
151 | 179 | @Override |
|
0 commit comments