47
47
import android .view .ViewParent ;
48
48
import android .view .accessibility .AccessibilityNodeInfo ;
49
49
import android .widget .EditText ;
50
+ import android .widget .FrameLayout ;
50
51
import android .widget .ImageButton ;
51
52
import android .widget .TextView ;
52
53
import androidx .annotation .ColorInt ;
@@ -136,6 +137,8 @@ public class SearchBar extends Toolbar {
136
137
private static final String NAMESPACE_APP = "http://schemas.android.com/apk/res-auto" ;
137
138
138
139
private final TextView textView ;
140
+ private final TextView placeholderTextView ;
141
+ private final FrameLayout textViewContainer ;
139
142
private final int backgroundColor ;
140
143
141
144
private boolean liftOnScroll ;
@@ -228,12 +231,18 @@ public SearchBar(@NonNull Context context, @Nullable AttributeSet attrs, int def
228
231
layoutInflated = true ;
229
232
230
233
textView = findViewById (R .id .open_search_bar_text_view );
234
+ placeholderTextView = findViewById (R .id .open_search_bar_placeholder_text_view );
235
+ textViewContainer = findViewById (R .id .open_search_bar_text_view_container );
231
236
232
237
setElevation (elevation );
233
238
initTextView (textAppearanceResId , text , hint );
234
239
initBackground (shapeAppearanceModel , backgroundColor , elevation , strokeWidth , strokeColor );
235
240
}
236
241
242
+ void setPlaceholderText (String string ) {
243
+ placeholderTextView .setText (string );
244
+ }
245
+
237
246
private void validateAttributes (@ Nullable AttributeSet attributeSet ) {
238
247
if (attributeSet == null ) {
239
248
return ;
@@ -273,6 +282,7 @@ private void initNavigationIcon() {
273
282
private void initTextView (@ StyleRes int textAppearanceResId , String text , String hint ) {
274
283
if (textAppearanceResId != -1 ) {
275
284
TextViewCompat .setTextAppearance (textView , textAppearanceResId );
285
+ TextViewCompat .setTextAppearance (placeholderTextView , textAppearanceResId );
276
286
}
277
287
setText (text );
278
288
setHint (hint );
@@ -423,7 +433,7 @@ protected void onLayout(boolean changed, int left, int top, int right, int botto
423
433
super .onLayout (changed , left , top , right , bottom );
424
434
425
435
if (centerView != null ) {
426
- layoutViewInCenter (centerView , /* absolutePlacement= */ true );
436
+ layoutViewInCenter (centerView );
427
437
}
428
438
setHandwritingBoundsInsets ();
429
439
if (textView != null ) {
@@ -432,7 +442,9 @@ protected void onLayout(boolean changed, int left, int top, int right, int botto
432
442
// to be pushed to the side. In this case, we want the textview to be still centered on top of
433
443
// any center views.
434
444
if (textCentered ) {
435
- layoutViewInCenter (textView , /* absolutePlacement= */ false );
445
+ // Make sure textview does not overlap with any toolbar views (nav icon, menu) or
446
+ // padding/insets
447
+ layoutTextViewCenterAvoidToolbarViewsAndPadding ();
436
448
}
437
449
}
438
450
}
@@ -581,52 +593,72 @@ private ImageButton findOrGetNavView() {
581
593
return navIconButton ;
582
594
}
583
595
596
+ private void layoutTextViewCenterAvoidToolbarViewsAndPadding () {
597
+ int textViewContainerLeft = getMeasuredWidth () / 2 - textViewContainer .getMeasuredWidth () / 2 ;
598
+ int textViewContainerRight = textViewContainerLeft + textViewContainer .getMeasuredWidth ();
599
+ int textViewContainerTop = getMeasuredHeight () / 2 - textViewContainer .getMeasuredHeight () / 2 ;
600
+ int textViewContainerBottom = textViewContainerTop + textViewContainer .getMeasuredHeight ();
601
+ boolean isRtl = getLayoutDirection () == LAYOUT_DIRECTION_RTL ;
602
+ View menuView = findOrGetMenuView ();
603
+ View navIconButton = findOrGetNavView ();
604
+
605
+ int textViewLeft = textViewContainer .getMeasuredWidth () / 2 - textView .getMeasuredWidth () / 2 ;
606
+ int textViewRight = textViewLeft + textView .getMeasuredWidth ();
607
+
608
+ // left and right refer to the textview's left and right coordinates within the searchbar
609
+ int left = textViewLeft + textViewContainerLeft ;
610
+ int right = textViewContainerLeft + textViewRight ;
611
+
612
+ View leftView = isRtl ? menuView : navIconButton ;
613
+ View rightView = isRtl ? navIconButton : menuView ;
614
+ int leftShift = 0 ;
615
+ int rightShift = 0 ;
616
+ if (leftView != null ) {
617
+ leftShift = max (leftView .getRight () - left , 0 );
618
+ }
619
+ left += leftShift ;
620
+ right += leftShift ;
621
+ if (rightView != null ) {
622
+ rightShift = max (right - rightView .getLeft (), 0 );
623
+ }
624
+ left -= rightShift ;
625
+ right -= rightShift ;
626
+ // Make sure to not lay out the view inside the SearchBar padding. paddingLeftAdded and
627
+ // paddingRightAdded will never be non-zero at the same time, as Toolbar.measure has already
628
+ // measured the children accounting for padding.
629
+ int paddingLeftShift = max (getPaddingLeft () - left , getContentInsetLeft () - left );
630
+ int paddingRightShift =
631
+ max (
632
+ right - (getMeasuredWidth () - getPaddingRight ()),
633
+ right - (getMeasuredWidth () - getContentInsetRight ()));
634
+ paddingLeftShift = max (paddingLeftShift , 0 );
635
+ paddingRightShift = max (paddingRightShift , 0 );
636
+
637
+ int totalShift = leftShift - rightShift + paddingLeftShift - paddingRightShift ;
638
+ // Center the textViewContainer and shift over textViewContainer by the amount that textView
639
+ // needs to be shifted over; this shifts both the container and the textView, which is necessary so the textView doesn't get
640
+ // laid outside of the container.
641
+ textViewContainer .layout (
642
+ textViewContainerLeft + totalShift ,
643
+ textViewContainerTop ,
644
+ textViewContainerRight + totalShift ,
645
+ textViewContainerBottom );
646
+ }
647
+
584
648
/**
585
649
* Lays out the given view in the center of the {@link SearchBar}.
586
650
*
587
651
* @param view The view to layout in the center.
588
- * @param absolutePlacement Whether the view will be placed absolutely in the center (eg. ignoring
589
- * other toolbar elements like the nav icon and menu, padding, content insets)
590
652
*/
591
- private void layoutViewInCenter (View view , boolean absolutePlacement ) {
653
+ private void layoutViewInCenter (View view ) {
592
654
if (view == null ) {
593
655
return ;
594
656
}
595
657
596
658
int viewWidth = view .getMeasuredWidth ();
597
659
int left = getMeasuredWidth () / 2 - viewWidth / 2 ;
598
660
int right = left + viewWidth ;
599
- if (!absolutePlacement ) {
600
- View menuView = findOrGetMenuView ();
601
- if (menuView != null ) {
602
- int diff =
603
- getLayoutDirection () == LAYOUT_DIRECTION_RTL
604
- ? max (menuView .getRight () - left , 0 )
605
- : max (right - menuView .getLeft (), 0 );
606
- left -= diff ;
607
- right -= diff ;
608
- }
609
- View navIcon = findOrGetNavView ();
610
- if (navIcon != null ) {
611
- int diff =
612
- getLayoutDirection () == LAYOUT_DIRECTION_RTL
613
- ? max (right - navIcon .getLeft (), 0 )
614
- : max (navIcon .getRight () - left , 0 );
615
- left += diff ;
616
- right += diff ;
617
- }
618
661
619
- // Make sure to not lay out the view inside the SearchBar padding. paddingLeftAdded and
620
- // paddingRightAdded will never be non-zero at the same time, as Toolbar.measure has already
621
- // measured the children accounting for padding.
622
- int paddingStartAdded = max (getPaddingStart () - left , getContentInsetStart () - left );
623
- int paddingEndAdded =
624
- max (
625
- right - (getMeasuredWidth () - getPaddingEnd ()),
626
- right - (getMeasuredWidth () - getContentInsetEnd ()));
627
- left += max (paddingStartAdded , 0 ) - max (paddingEndAdded , 0 );
628
- right += max (paddingStartAdded , 0 ) - max (paddingEndAdded , 0 );
629
- }
630
662
int viewHeight = view .getMeasuredHeight ();
631
663
int top = getMeasuredHeight () / 2 - viewHeight / 2 ;
632
664
int bottom = top + viewHeight ;
@@ -690,6 +722,10 @@ public void setCenterView(@Nullable View view) {
690
722
}
691
723
}
692
724
725
+ TextView getPlaceholderTextView () {
726
+ return placeholderTextView ;
727
+ }
728
+
693
729
/** Returns the main {@link TextView} which can be used for hint and search text. */
694
730
@ NonNull
695
731
public TextView getTextView () {
@@ -705,26 +741,31 @@ public CharSequence getText() {
705
741
/** Sets the text of main {@link TextView}. */
706
742
public void setText (@ Nullable CharSequence text ) {
707
743
textView .setText (text );
744
+ placeholderTextView .setText (text );
708
745
}
709
746
710
747
/** Sets the text of main {@link TextView}. */
711
748
public void setText (@ StringRes int textResId ) {
712
749
textView .setText (textResId );
750
+ placeholderTextView .setText (textResId );
713
751
}
714
752
715
- /** Whether or not to center the text. */
753
+ /** Whether or not to center the text within the TextView . */
716
754
public void setTextCentered (boolean textCentered ) {
717
755
this .textCentered = textCentered ;
718
756
if (textView == null ) {
719
757
return ;
720
758
}
721
- Toolbar .LayoutParams lp = (LayoutParams ) textView .getLayoutParams ();
759
+ FrameLayout .LayoutParams lp = (FrameLayout . LayoutParams ) textView .getLayoutParams ();
722
760
if (textCentered ) {
761
+ lp .gravity = Gravity .CENTER_HORIZONTAL ;
723
762
textView .setGravity (Gravity .CENTER_HORIZONTAL );
724
763
} else {
764
+ lp .gravity = Gravity .NO_GRAVITY ;
725
765
textView .setGravity (Gravity .NO_GRAVITY );
726
766
}
727
767
textView .setLayoutParams (lp );
768
+ placeholderTextView .setLayoutParams (lp );
728
769
}
729
770
730
771
/** Whether or not the text is centered. */
@@ -735,6 +776,7 @@ public boolean getTextCentered() {
735
776
/** Clears the text of main {@link TextView}. */
736
777
public void clearText () {
737
778
textView .setText ("" );
779
+ placeholderTextView .setText ("" );
738
780
}
739
781
740
782
/** Returns the hint of main {@link TextView}. */
0 commit comments