Изменения плавающего действия кнопки привязки при создании вида

У меня возникла проблема с тем, что FAB привязана к списку ( см. Пример видео ), похоже, мерцает на ничью, изменяя позицию привязки. Проблема возникает в эмуляторе, а также на любом устройстве, которое я тестировал на уровне 19 API-сообщений.

У меня есть основная деятельность:

<LinearLayout android:id="@+id/main_layout" android:orientation="vertical" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <!-- our toolbar --> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="?attr/colorPrimary" android:minHeight="?attr/actionBarSize" android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" app:popupTheme="@style/ThemeOverlay.AppCompat.Light" android:elevation="4dp"/> <!-- our tablayout to display tabs --> <android.support.design.widget.TabLayout android:id="@+id/tabLayout" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="?attr/colorPrimary" android:minHeight="?attr/actionBarSize" android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" android:elevation="4dp"/> <!-- View pager to swipe views --> <android.support.v4.view.ViewPager android:id="@+id/pager" android:layout_width="match_parent" android:layout_height="fill_parent" /> </LinearLayout> 

Что тогда держит нижнюю навигацию

 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:background="#fff"> <FrameLayout android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:id="@+id/svBody" android:background="#fff"> </FrameLayout> <android.support.design.widget.BottomNavigationView android:id="@+id/bottomNavigation" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="bottom" app:itemBackground="@color/colorPrimary" android:background="@color/colorPrimary" app:itemIconTint="@color/cardview_light_background" app:itemTextColor="@color/cardview_light_background" app:menu="@menu/bottom_navigation_main"> </android.support.design.widget.BottomNavigationView> </LinearLayout> 

Что содержит фрагмент:

 <android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/lvWords" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:background="#fff"> <LinearLayout android:layout_width="match_parent" android:layout_height="50dp" android:orientation="horizontal" android:background="#fff" android:elevation="4dp"> <TextView android:text="Lipshapes" android:layout_width="wrap_content" android:layout_height="50dp" android:id="@+id/lipshapes_titlestrip" android:background="#33b5e5" android:textColor="#fff" android:textSize="32sp" android:paddingTop="4dp" android:paddingBottom="4dp" android:elevation="6dp" android:paddingLeft="@dimen/margin_medium" android:paddingRight="@dimen/margin_medium"/> <TextView android:id="@+id/words_titlestrip" android:layout_width="0dp" android:layout_height="match_parent" android:layout_gravity="bottom|right" android:layout_weight="1" android:background="#059FD8" android:elevation="10dp" android:paddingBottom="4dp" android:paddingLeft="@dimen/margin_medium" android:paddingRight="@dimen/margin_medium" android:paddingTop="4dp" android:text="Words" android:textColor="#fff" android:textSize="32sp" /> </LinearLayout> <LinearLayout android:layout_width="wrap_content" android:layout_height="0dp" android:orientation="vertical" android:layout_weight="1" android:elevation="0dp" android:background="#fff"> <ListView android:id="@android:id/list" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" /> <View android:id="@+id/view" android:layout_width="match_parent" android:layout_height="4dp" android:background="@drawable/shadow" /> </LinearLayout> </LinearLayout> <android.support.design.widget.FloatingActionButton android:id="@+id/fab" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="bottom|right" android:layout_margin="16dp" android:src="@drawable/plus_white_48" app:layout_anchor="@android:id/list" app:layout_anchorGravity="bottom|right|end" app:fabSize="normal" /> 

И вот код фрагментов:

 public static class WordListSectionFragment extends ListFragment implements AdapterView.OnItemClickListener, AdapterView.OnItemLongClickListener, View.OnClickListener, LoaderManager.LoaderCallbacks<Cursor> { public SimpleCursorAdapter wordAdapter; final static int LIST_VIEW = 0; private FloatingActionButton fab; String lipshape = null; int lipshape_id = 0; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.fragment_section_wordlist, container, false); fab = (FloatingActionButton) rootView.findViewById(R.id.fab); Bundle args = getArguments(); lipshape = args.getString("lipshape_selected_desc"); lipshape_id = Integer.valueOf(args.getString("lipshape_selected_id")); ((TextView) rootView.findViewById(R.id.words_titlestrip)).setText( lipshape ); TextView lipshapesTV = (TextView) rootView.findViewById(R.id.lipshapes_titlestrip); lipshapesTV.setOnClickListener(this); return rootView; } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); // if you only want one column do it like this // String[] projection = new String[]{BaseColumns._ID, VideoFilesContract.videoFiles.FILENAME}; wordAdapter = new SimpleCursorAdapter( getContext(), R.layout.item_word, null, new String[] {WordContract.wordItems.DESCRIPTION, "number_of_videos"}, new int[] {R.id.tvWord, R.id.tvVideoCount}, LIST_VIEW); // Setup cursor adapter using cursor from last step setListAdapter(wordAdapter); //getListView().setOnItemClickListener(this); getLoaderManager().initLoader(LIST_VIEW, null, this); } @Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); getListView().setOnItemClickListener(this); getListView().setOnItemLongClickListener(this); fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { // Click action //Toast.makeText(getActivity(), "Button Clicked!", Toast.LENGTH_SHORT).show(); Intent intent = new Intent(getActivity(), AddWord.class); intent.putExtra("lipshape_selected_id", lipshape_id); intent.putExtra("lipshape_selected_desc", lipshape); startActivityForResult(intent, 1); } }); } public void restartLoader() { wordAdapter.swapCursor(null); getLoaderManager().restartLoader(LIST_VIEW, null, this); } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); switch(requestCode) { case (1) : { if (resultCode == Activity.RESULT_OK) { Boolean returnValue = data.getBooleanExtra("added_word", false); if (returnValue) { restartLoader(); Snackbar.make(getView().getRootView().findViewById(R.id.lvWords), "Word Added Successfully!", Snackbar.LENGTH_LONG) .setAction("Action", null).show(); } } break; } } } @Override public void onClick(View v) { if (v.getId() == R.id.lipshapes_titlestrip) { LipshapeSectionFragment fragment = new LipshapeSectionFragment(); FragmentManager fragmentManager = getFragmentManager(); fragmentManager.beginTransaction().replace(R.id.svBody, fragment).commit(); } } @Override public void onItemClick(AdapterView<?> adapterView, View view, int position,long id) { Cursor _cursor = ((Cursor) getListView().getItemAtPosition(position)); Cursor cursor; int count =0; //do a count for videos if 0 int word_id = _cursor.getInt(_cursor.getColumnIndex("_id")); String word = _cursor.getString(_cursor.getColumnIndex(WordContract.wordItems.DESCRIPTION)); ContentResolver resolver = getContext().getContentResolver(); if (word_id!=0) { cursor = resolver.query(VideoFilesContract.videoFiles.CONTENT_URI, VideoFilesContract.videoFiles.PROJECTION_ALL, "word_id=?", new String[]{Integer.toString(word_id)}, null, null); count = cursor.getCount(); } switch(count) { case 0: Snackbar.make(view, "There are no videos recorded with this word.", Snackbar.LENGTH_LONG) .setAction("Action", null).show(); break; default: Intent intent = new Intent(getActivity(), CollectionDemoActivity.class); intent.putExtra("word_id", word_id); intent.putExtra("word", word); startActivity(intent); } //Toast.makeText(getActivity(), "Item: " + test, Toast.LENGTH_SHORT).show(); } @Override public Loader<Cursor> onCreateLoader(int id, Bundle bundle) { CursorLoader loader = null; Bundle args = getArguments(); switch (id) { case LIST_VIEW: loader = new CursorLoader( this.getActivity(), WordContract.wordItems.CONTENT_TEST, new String[]{WordContract.wordItems._ID, WordContract.wordItems.DESCRIPTION, "number_of_videos"}, null, new String[]{args.getString("lipshape_selected_id")}, null); return loader; default: return loader; } } @Override public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) { ((SimpleCursorAdapter)this.getListAdapter()). swapCursor(cursor); } @Override public void onLoaderReset(Loader<Cursor> loader) { ((SimpleCursorAdapter)this.getListAdapter()). swapCursor(null); } public void showDialog(final int word_id, String word_clicked) { AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); builder.setTitle("Delete Word: "+ word_clicked + "?"); builder.setMessage("Deleting this word will also delete all videos tagged by this word."); String positiveText = "Delete"; builder.setPositiveButton(positiveText, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { deleteWord(word_id); //reload } }); String negativeText = getString(android.R.string.cancel); builder.setNegativeButton(negativeText, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { // negative button logic } }); AlertDialog dialog = builder.create(); // display dialog dialog.show(); } public boolean deleteWord(int word_id) { ContentResolver resolver = getContext().getContentResolver(); Uri delUri = ContentUris.withAppendedId(WordContract.wordItems.CONTENT_URI, word_id); //resolver.delete(VideoFilesContract.videoFiles.CONTENT_URI, "_id=?", selectionArgs); long resultCount = resolver.delete(delUri, null, null); if (resultCount == 0) { //couldn't delete word with that id return false; } else { restartLoader(); Snackbar.make(getListView(), "Word deleted successfully.", Snackbar.LENGTH_LONG) .setAction("Action", null).show(); return true; } } @Override public boolean onItemLongClick(AdapterView<?> adapterView, View view, int i, long l) { //Snackbar.make(view, "Item has been long clicked!", Snackbar.LENGTH_LONG) // .setAction("Action", null).show(); Cursor _cursor = ((Cursor) getListView().getItemAtPosition(i)); Cursor cursor; int count =0; //do a count for videos if 0 int word_id = _cursor.getInt(_cursor.getColumnIndex("_id")); String word = _cursor.getString(_cursor.getColumnIndex(WordContract.wordItems.DESCRIPTION)); showDialog(word_id, word); return true; } } 

Solutions Collecting From Web of "Изменения плавающего действия кнопки привязки при создании вида"

Я не мог найти более чистое исправление, чем установить видимость FAB на начальном этапе, но установив привязку к списку:

 <android.support.design.widget.FloatingActionButton android:id="@+id/fab" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="bottom|right|end" android:layout_margin="16dp" android:src="@drawable/plus_white_48" android:visibility="gone" app:layout_anchor="@android:id/list" app:layout_anchorGravity="bottom|right|end" app:fabSize="normal" /> 

И тогда, если список не пуст после того, как курсор закончил загрузку, просто сделайте его видимым, и он закрепляется как указано выше, а в случаях, когда lis пуст, мы устанавливаем параметры макета для привязки в пустом списке:

 if (wordAdapter.getCursor().getCount()<1) { //the linear layout for the empty list view state ll.setVisibility(View.VISIBLE); //set the text of this to be visible too, default is invisible as otherwise it's visible when the list is loading tvFeedback.setVisibility(View.VISIBLE); CoordinatorLayout.LayoutParams p (CoordinatorLayout.LayoutParams) fab.getLayoutParams(); p.setAnchorId(R.id.empty_list_view); fab.setLayoutParams(p); fab.setVisibility(View.VISIBLE); } 

Это приводит к не мерцанию при загрузке, также приводит к тому, что якорь всегда находится в правильном месте, даже если элементы из списка удалены.

Вы видите FAB в левом верхнем углу, потому что в этот момент ListView не отображается в ListView . Когда элементы заполняются, ListView соответствует его родительскому элементу, и FAB позиционируется правильно.

Прикрепите якорь FAB к родительскому, который уже соответствует всему пространству, и удерживает ваш ListView .

Что-то вроде этого

 <LinearLayout **android:id="@+id/list_parent"** android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:background="#fff"> <LinearLayout android:layout_width="match_parent" android:layout_height="50dp" android:orientation="horizontal" android:background="#fff" android:elevation="4dp"> <TextView android:text="Lipshapes" android:layout_width="wrap_content" android:layout_height="50dp" android:id="@+id/lipshapes_titlestrip" android:background="#33b5e5" android:textColor="#fff" android:textSize="32sp" android:paddingTop="4dp" android:paddingBottom="4dp" android:elevation="6dp" android:paddingLeft="@dimen/margin_medium" android:paddingRight="@dimen/margin_medium"/> <TextView android:id="@+id/words_titlestrip" android:layout_width="0dp" android:layout_height="match_parent" android:layout_gravity="bottom|right" android:layout_weight="1" android:background="#059FD8" android:elevation="10dp" android:paddingBottom="4dp" android:paddingLeft="@dimen/margin_medium" android:paddingRight="@dimen/margin_medium" android:paddingTop="4dp" android:text="Words" android:textColor="#fff" android:textSize="32sp" /> </LinearLayout> <LinearLayout android:layout_width="wrap_content" android:layout_height="0dp" android:orientation="vertical" android:layout_weight="1" android:elevation="0dp" android:background="#fff"> <ListView android:id="@android:id/list" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" /> <View android:id="@+id/view" android:layout_width="match_parent" android:layout_height="4dp" android:background="@drawable/shadow" /> </LinearLayout> </LinearLayout> <android.support.design.widget.FloatingActionButton android:id="@+id/fab" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="bottom|right" android:layout_margin="16dp" android:src="@drawable/plus_white_48" app:layout_anchor="@+id/list_parent" app:layout_anchorGravity="bottom|right|end" app:fabSize="normal" /> 

Дружелюбный совет, переключитесь на RecyclerView .