1818
1919import io .material .catalog .R ;
2020
21- import android .annotation .SuppressLint ;
2221import android .os .Build .VERSION ;
2322import android .os .Build .VERSION_CODES ;
2423import android .os .Bundle ;
2524import androidx .fragment .app .Fragment ;
2625import androidx .appcompat .app .AppCompatActivity ;
2726import androidx .recyclerview .widget .GridLayoutManager ;
2827import androidx .recyclerview .widget .RecyclerView ;
28+ import android .support .v7 .widget .SearchView ;
29+ import android .support .v7 .widget .SearchView .OnQueryTextListener ;
2930import androidx .appcompat .widget .Toolbar ;
3031import android .util .DisplayMetrics ;
3132import android .view .LayoutInflater ;
3233import android .view .View ;
3334import android .view .ViewGroup ;
3435import android .widget .ImageButton ;
36+ import androidx .annotation .Dimension ;
37+ import androidx .annotation .NonNull ;
3538import androidx .annotation .Nullable ;
39+ import androidx .constraintlayout .widget .ConstraintLayout ;
40+ import androidx .constraintlayout .widget .ConstraintSet ;
3641import androidx .core .content .ContextCompat ;
3742import androidx .core .math .MathUtils ;
3843import androidx .core .view .ViewCompat ;
44+ import androidx .transition .Transition ;
45+ import androidx .transition .TransitionManager ;
3946import com .google .android .material .appbar .AppBarLayout ;
47+ import com .google .android .material .transition .MaterialSharedAxis ;
4048import dagger .android .support .DaggerFragment ;
4149import io .material .catalog .feature .FeatureDemo ;
4250import io .material .catalog .feature .FeatureDemoUtils ;
@@ -54,13 +62,21 @@ public class TocFragment extends DaggerFragment {
5462 private static final int GRID_SPAN_COUNT_MIN = 1 ;
5563 private static final int GRID_SPAN_COUNT_MAX = 4 ;
5664
65+ @ Dimension (unit = Dimension .DP )
66+ private static final int CATALOG_NARROW_SCREEN_SIZE_CUTOFF = 350 ;
67+
5768 @ Inject Set <FeatureDemo > featureDemos ;
5869 @ Inject TocResourceProvider tocResourceProvider ;
5970
6071 private AppBarLayout appBarLayout ;
6172 private View gridTopDivider ;
62- private RecyclerView recyclerView ;
73+ private ConstraintLayout headerContainer ;
6374 private ImageButton preferencesButton ;
75+ private SearchView searchView ;
76+ private ImageButton searchButton ;
77+ private TocAdapter tocAdapter ;
78+ private Transition openSearchViewTransition ;
79+ private Transition closeSearchViewTransition ;
6480
6581 @ Override
6682 public void onCreate (@ Nullable Bundle bundle ) {
@@ -71,9 +87,9 @@ public void onCreate(@Nullable Bundle bundle) {
7187 }
7288 }
7389
74- @ SuppressLint ("MissingInflatedId" )
7590 @ Nullable
7691 @ Override
92+ @ SuppressWarnings ("MissingInflatedId" )
7793 public View onCreateView (
7894 LayoutInflater layoutInflater , @ Nullable ViewGroup viewGroup , @ Nullable Bundle bundle ) {
7995 View view =
@@ -85,12 +101,18 @@ public View onCreateView(
85101 activity .getSupportActionBar ().setDisplayShowTitleEnabled (false );
86102
87103 ViewGroup content = view .findViewById (R .id .content );
88- View .inflate (getContext (), tocResourceProvider . getHeaderContent () , content );
104+ View .inflate (getContext (), R . layout . cat_toc_header , content );
89105
90106 appBarLayout = view .findViewById (R .id .cat_toc_app_bar_layout );
91107 gridTopDivider = view .findViewById (R .id .cat_toc_grid_top_divider );
92- recyclerView = view .findViewById (R .id .cat_toc_grid );
108+ headerContainer = view .findViewById (R .id .cat_toc_header_container );
109+ RecyclerView recyclerView = view .findViewById (R .id .cat_toc_grid );
93110 preferencesButton = view .findViewById (R .id .cat_toc_preferences_button );
111+ searchView = view .findViewById (R .id .cat_toc_search_view );
112+ searchButton = view .findViewById (R .id .cat_toc_search_button );
113+
114+ // Inflate logo into the header container.
115+ View .inflate (getContext (), tocResourceProvider .getLogoLayout (), headerContainer );
94116
95117 ViewCompat .setOnApplyWindowInsetsListener (
96118 view ,
@@ -126,14 +148,46 @@ public View onCreateView(
126148 getContext ().getString (feature1 .getTitleResId ()),
127149 getContext ().getString (feature2 .getTitleResId ())));
128150
129- TocAdapter tocAdapter = new TocAdapter (getActivity (), featureList );
151+ tocAdapter = new TocAdapter (getActivity (), featureList );
130152 recyclerView .setAdapter (tocAdapter );
131153
154+ adjustLogoConstraintsForNarrowScreenWidths ();
155+
132156 initPreferencesButton ();
157+ initSearchButton ();
158+ initSearchView ();
159+ initSearchViewTransitions ();
133160
134161 return view ;
135162 }
136163
164+ private void adjustLogoConstraintsForNarrowScreenWidths () {
165+ // Adjust logo constraints so that the logo text does not overlap with the search image button.
166+ if (getScreenWidth () < CATALOG_NARROW_SCREEN_SIZE_CUTOFF ) {
167+ ConstraintSet narrowHeaderConstraintSet = createNarrowHeaderConstraintSet (headerContainer );
168+ narrowHeaderConstraintSet .applyTo (headerContainer );
169+ }
170+ }
171+
172+ @ Dimension (unit = Dimension .DP )
173+ private int getScreenWidth () {
174+ return getResources ().getConfiguration ().screenWidthDp ;
175+ }
176+
177+ private ConstraintSet createNarrowHeaderConstraintSet (ConstraintLayout constraintLayout ) {
178+ ConstraintSet constraintSet = new ConstraintSet ();
179+ constraintSet .clone (constraintLayout );
180+ constraintSet .connect (
181+ R .id .header_logo , ConstraintSet .END , R .id .cat_toc_search_button , ConstraintSet .START );
182+ // Add a bit of space on the start side of the logo to compensate for the extra 12dp of space
183+ // the search icon button includes on each side because of its 48dp minimum touch target width.
184+ constraintSet .setMargin (
185+ R .id .header_logo ,
186+ ConstraintSet .START ,
187+ getResources ().getDimensionPixelOffset (R .dimen .cat_toc_header_additional_start_margin ));
188+ return constraintSet ;
189+ }
190+
137191 private void addGridTopDividerVisibilityListener () {
138192 appBarLayout .addOnOffsetChangedListener (
139193 (appBarLayout , verticalOffset ) -> {
@@ -157,8 +211,76 @@ private int calculateGridSpanCount() {
157211
158212 private void initPreferencesButton () {
159213 preferencesButton .setOnClickListener (
160- v -> new CatalogPreferencesDialogFragment ().show (
161- getParentFragmentManager (), "preferences-screen" ));
214+ v ->
215+ new CatalogPreferencesDialogFragment ()
216+ .show (getParentFragmentManager (), "preferences-screen" ));
217+ }
218+
219+ private void initSearchButton () {
220+ searchButton .setOnClickListener (v -> openSearchView ());
221+ }
222+
223+ private void initSearchView () {
224+ searchView .setOnClickListener (v -> closeSearchView ());
225+
226+ searchView .setOnQueryTextListener (
227+ new OnQueryTextListener () {
228+ @ Override
229+ public boolean onQueryTextSubmit (String query ) {
230+ return false ;
231+ }
232+
233+ @ Override
234+ public boolean onQueryTextChange (String newText ) {
235+ tocAdapter .getFilter ().filter (newText );
236+ return false ;
237+ }
238+ });
239+ }
240+
241+ private void initSearchViewTransitions () {
242+ openSearchViewTransition = createSearchViewTransition (true );
243+ closeSearchViewTransition = createSearchViewTransition (false );
244+ }
245+
246+ private void openSearchView () {
247+ TransitionManager .beginDelayedTransition (headerContainer , openSearchViewTransition );
248+
249+ headerContainer .setVisibility (View .GONE );
250+ searchView .setVisibility (View .VISIBLE );
251+
252+ searchView .requestFocus ();
253+ }
254+
255+ private void closeSearchView () {
256+ TransitionManager .beginDelayedTransition (headerContainer , closeSearchViewTransition );
257+
258+ headerContainer .setVisibility (View .VISIBLE );
259+ searchView .setVisibility (View .GONE );
260+
261+ clearSearchView ();
262+ }
263+
264+ @ NonNull
265+ private MaterialSharedAxis createSearchViewTransition (boolean entering ) {
266+ MaterialSharedAxis sharedAxisTransition =
267+ new MaterialSharedAxis (MaterialSharedAxis .X , entering );
268+
269+ sharedAxisTransition .addTarget (headerContainer );
270+ sharedAxisTransition .addTarget (searchView );
271+ return sharedAxisTransition ;
272+ }
273+
274+ @ Override
275+ public void onPause () {
276+ super .onPause ();
277+ clearSearchView ();
278+ }
279+
280+ private void clearSearchView () {
281+ if (searchView != null ) {
282+ searchView .setQuery ("" , true );
283+ }
162284 }
163285
164286 private void startDefaultDemoLandingIfNeeded () {
0 commit comments