Hi I an trying to implement [FloatingActionButton][1] Library by makovkastar. (As it is backward compatible. It works fine with single FAB, but when 2 Buttons are added, the "List" seems to get attached to only one buttons.
fragment_listview.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:fab="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:id="#android:id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:cacheColorHint="#android:color/transparent"
android:headerDividersEnabled="false"/>
<com.melnykov.fab.FloatingActionButton
android:id="#+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|right"
android:layout_margin="16dp"
android:src="#drawable/ic_add_white_24dp"
fab:fab_colorNormal="#color/accent"
fab:fab_colorPressed="#color/accent_pressed"
fab:fab_colorRipple="#color/ripple"/>
<com.melnykov.fab.FloatingActionButton
android:id="#+id/fab2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|left"
android:layout_margin="16dp"
android:src="#drawable/ic_add_white_24dp"
fab:fab_colorNormal="#color/accent"
fab:fab_colorPressed="#color/accent_pressed"
fab:fab_colorRipple="#color/ripple"/>
</FrameLayout>
MainActivity ListViewFragment Class
public static class ListViewFragment extends Fragment {
#SuppressLint("InflateParams")
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_listview, container, false);
ListView list = (ListView) root.findViewById(android.R.id.list);
ListViewAdapter listAdapter = new ListViewAdapter(getActivity(),
getResources().getStringArray(R.array.countries));
list.setAdapter(listAdapter);
FloatingActionButton fab = (FloatingActionButton) root.findViewById(R.id.fab);
fab.attachToListView(list);
FloatingActionButton fab2 = (FloatingActionButton) root.findViewById(R.id.fab2);
fab2.attachToListView(list);
return root;
}
This is same code sample provided in that library:
When the list is scrolled, only one button (fab2 in this case) becomes invisible when scrolled down. I want both the buttons to react to scroll.
Any idea to anyone how this can be done?
Thanks in advance.
You can do this yourself, by making your fragment implement com.melnykov.fab.ScrollDirectionListener (also from the same package as the fab).
public static class ListViewFragment extends Fragment implements
com.melnykov.fab.ScrollDirectionListener {
private FloatingActionButton fab, fab2;
#SuppressLint("InflateParams")
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_listview, container, false);
ListView list = (ListView) root.findViewById(android.R.id.list);
ListViewAdapter listAdapter = new ListViewAdapter(getActivity(),
getResources().getStringArray(R.array.countries));
list.setAdapter(listAdapter);
fab = (FloatingActionButton) root.findViewById(R.id.fab);
// this method expects a ScrollDirectionListener as second arg
// so use this for that parameter
fab.attachToListView(list, this);
fab2 = (FloatingActionButton) root.findViewById(R.id.fab2);
fab2.attachToListView(list, this);
return root;
}
#Override
public void onScrollDown() {
if (fab.isVisible() || fab2.isVisible()) {
fab.hide();
fab2.hide();
}
}
#Override
public void onScrollUp() {
if (!fab.isVisible() || !fab2.isVisible()) {
fab.show();
fab2.show();
}
}
}
I'm sure this should work, but in the case it doesn't you should open an issue to propose this possible bug to the developer.
Note
Android now has it's own implementation of the FloatingActionButton (and much more) in the design library. Include it in your project with this:
compile 'com.android.support:design:22.2.0'
Here is an excellent guide for using the new FAB with lists; it even includes use of the new CoordinatorLayout which should replace need for scroll listeners and such
Related
I'm currently trying to implement my first ever RecyclerView in Xamarin.Android.
In my main layout file, i have a DrawerLayout which contains a FrameLayout and a ListView. What i am trying to achieve is that each time an item from the ListView is clicked, a Fragment containing a RecyclerView will be loaded using the FragmentManager.
The issue i face is that each time i return from OnCreateView in the Fragment, i get the above exception.
What confuses me most is that when i step through the code in OnCreateView, FindViewById does not throw an exception and seems to populate recyclerView correctly.
Any help will be greatly appreciated. Thank you.
DiscoverNew.axml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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.support.v7.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</RelativeLayout>
DiscoverNewFragment.cs
public class DiscoverNewFragment : Fragment
{
RecyclerView recyclerView;
IngredientsAdapter ingredientsAdapter;
List<Ingredients> listOfIngredients;
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
var view = inflater.Inflate(Resource.Layout.DiscoverNew, container, false);
recyclerView = view.FindViewById(Resource.Id.recyclerView) as RecyclerView;
var layoutMan = new GridLayoutManager(recyclerView.Context, 2, GridLayoutManager.Vertical, false);
recyclerView.SetLayoutManager(layoutMan);
listOfIngredients = IngredientsData.LoadIngredients(this.Activity);
ingredientsAdapter = new IngredientsAdapter(listOfIngredients);
recyclerView.SetAdapter(ingredientsAdapter);
return view;
}
}
MainActivity.cs
[Activity(Label = "MyApp", Theme = "#style/AppTheme", MainLauncher = true)]
public class MainActivity : AppCompatActivity
{
. . .
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.Main);
. . .
OnMenuItemClick(0); // Load Fragment 0 at startup
}
. . .
void OnMenuItemClick(int position)
{
base.FragmentManager.BeginTransaction().Replace(Resource.Id.frameLayout, new DiscoverNewFragment()).Commit();
this.Title = "Discover";
drawerLayout.CloseDrawer(drawerListView);
}
}
NB: i have omitted some code from MainActivity.cs which is related to the setting up of the drawer layout
I have just resolved this issue by reverting the following nuget package from version 27.0.2.1 to version 26.1.0.1:- xamarin.android.support.design
I know it's more of a work around than a solution but after trying different things, this was the only option that seemed to work.
I have two fragments on top of each other when I call the second fragment I still the buttons from the first fragment stay visible and functional.
I tried many many methods but didn't work
This one gave me this error:
java.lang.IllegalArgumentException: No view found for id 0x7f0e0004 (*.test:id/customId) for fragment SecondFragment{adef947 #0 id=0x7f0e0004}
and This
java.lang.IllegalArgumentException: No view found for id 0x7f0e00ae (sy.aya.ayaisp.test:id/gatesViewpager) for fragment SecondSFragment{adef947 #0 id=0x7f0e00ae}
my code is as follows:
FirstFragment.java
public View onCreateView(LayoutInflater inflater, final ViewGroup container, Bundle savedInstanceState) {
View myView = inflater.inflate(R.layout.first_fragment, container, false);
Button FBtn = (Button) myView.findViewById(R.id.Fbutton);
FBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Bundle bundle = new Bundle();
bundle.putString("second", "f button");
SecondFragment secondFragment = new secondFragment();
secondFragment.setArguments(bundle);
FragmentTransaction ft = getChildFragmentManager().beginTransaction();
ft.setCustomAnimations(R.anim.slide_in_up, R.anim.slide_in_up);
ft.replace(R.id.s_con, secondFragment).addToBackStack("back").commit();
}
});
SecondFrag.java
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
String bundleString = this.getArguments().getString("second");
View view = inflater.inflate(R.layout.s_rv, container, false);
RecyclerView recyclerView = (RecyclerView) view.findViewById(R.id.s_recyclerview);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
if (bundleString == "agents button") {
recyclerView.setAdapter(new SecondAdapter(getContext()));
}
}
first_fragment.xml
<android.support.constraint.ConstraintLayout 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:id="#+id/s_con"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="#+id/Fbutton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="secondFragment"/>
</android.support.constraint.ConstraintLayout>
s_rv.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<sy.aya.ayaisp.ExpandableRecyclerView
android:id="#+id/s_recyclerview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="5dp"
android:clipToPadding="false"
android:scrollbars="vertical" />
</FrameLayout>
Thank you for your help
In second fragment layout "s_rv" in root element of xml add some background, clickable="true" and focusable="true".
And in first fragment layout wrap your button in LinearLayout. two days back I was also facing same issue it was solved after that.
It is because in your first fragment the id of button is "pos_agents_button" but in findViewById you are trying to find "R.id.Fbutton".
Change
Button FBtn = (Button) myView.findViewById(R.id.Fbutton);
to
Button FBtn = (Button) myView.findViewById(R.id.pos_agents_button);
and everything should work fine.
How to handle empty data View in a RecyclerView ,I have tried so many ways from internet but none seems to work. I am also using realm database so I don't know if this is the right way to check if it is empty or not.
this is my Fragment xml where the RecyclerView is located
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/tv_no_data"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/holo_green_dark"
android:gravity="center"
android:text="emptty"
android:textAppearance="?android:textAppearanceMedium"
android:textColor="#android:color/white"
android:visibility="invisible" />
<android.support.v7.widget.RecyclerView
android:id="#+id/rv_favorite"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/colorPrimaryDark">
</android.support.v7.widget.RecyclerView>
</FrameLayout>
and this is my fragment class
public class FavouriteFragment extends Fragment {
RecyclerView mRecyclerView;
FavouriteAdapter adapter;
Realm mRealm;
int positions;
TextView emptyText;
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view=inflater.inflate(R.layout.favourite_fragment,container,false);
mRealm=Realm.getDefaultInstance();
RealmQuery<news> quotesRealmQuery = mRealm.where(News.class).equalTo("favourite",true);
RealmResults<News> mResults = newsRealmQuery.findAll();
emptyText= (TextView) view.findViewById(R.id.tv_no_data);
//adapter=new FavouriteAdapter(getActivity(),mResults,mRealm);
mRecyclerView= (RecyclerView) view.findViewById(R.id.rv_favorite);
mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
if (!mResults.isEmpty()) {
//if data is available, don't show the empty text
emptyText.setVisibility(View.INVISIBLE);
adapter=new FavouriteAdapter(getActivity(),mResults,mRealm,pos,single);
mRecyclerView.setAdapter(adapter);
mRealm.addChangeListener(new RealmChangeListener<Realm>() {
#Override
public void onChange(Realm element) {
adapter.notifyItemRemoved(positions);
}
});
} else
emptyText.setVisibility(View.VISIBLE);
return view;
}
Your RecyclerView is not transparent so you should remember to hide it when is empty:
if (!mResults.isEmpty()) {
//if data is available, don't show the empty text
emptyText.setVisibility(View.INVISIBLE);
mRecyclerView.setVisibility(View.VISIBLE);
} else {
emptyText.setVisibility(View.VISIBLE);
mRecyclerView.setVisibility(View.GONE);
}
First off; I would like to apologize for the lengthy question. I though this was the only way to get across what I am trying to do. Anyway. I have an app that user a navigation drawer that will offer a user 3 choices. I want Test1Fragment to be a listview. I can not seem to figure out how to make this happen. Please help.
MainActivity method that controls which fragment is loaded based on the selection:
private void selectItem(int position) {
// update the main content by replacing fragments
Fragment fragment = null;
switch (position) {
case 0:
fragment = new Test1Fragment();
break;
case 1:
fragment = new Test2Fragment();
break;
case 2:
fragment = new Test3Fragment();
break;
default:
break;
}
if (fragment != null) {
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction().replace(R.id.content_frame, fragment).commit();
// update selected item and title, then close the drawer
mDrawerList.setItemChecked(position, true);
mDrawerList.setSelection(position);
setTitle(mNavigationDrawerItemTitles[position]);
mDrawerLayout.closeDrawer(mDrawerList);
} else {
// error in creating fragment
Log.e("MainActivity", "Error in creating fragment");
}
}
Test1Fragment:
public class Test1Fragment extends Fragment {
public Test1Fragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_create, container, false);
return rootView;
}
fragment_create.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<!--<TextView-->
<!--android:id="#+id/txtLabel"-->
<!--android:layout_width="wrap_content"-->
<!--android:layout_height="wrap_content"-->
<!--android:layout_centerInParent="true"-->
<!--android:text="Create View"-->
<!--android:textSize="16dp" />-->
<!--<ImageView-->
<!--android:layout_width="wrap_content"-->
<!--android:layout_height="wrap_content"-->
<!--android:layout_below="#id/txtLabel"-->
<!--android:layout_centerHorizontal="true"-->
<!--android:layout_marginTop="10dp"-->
<!--android:src="#drawable/ic_action_copy" />-->
<ListView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/listView"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true" />
</RelativeLayout>
I understand that I am missing code for the listview, but this is all I want int the xml view.
Thank you
In your current implementation, your layout code should look in example like that:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:id="#+id/layout_fragment_listView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
</LinearLayout>
Then in your class, you must fill listview with data. You have to create adapter and attach data to this adapter. Then adapter must be passed to listview.
Quick example :
public class Test1Fragment extends Fragment {
//No need for empty constructor, it is made by default
//public Test1Fragment() {
//}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_create, container, false);
ListView listView =(ListView)rootView.findViewById(R.id.layout_fragment_listView);
String[] items = { "Milk", "Cheese", "Cucumber", "Toilet", "Duck" };
ArrayAdapter<String> adapter = new ArrayAdapter<String>(getActivity(),
android.R.layout.simple_list_item_1, items);
listView.setAdapter(adapter);
return rootView;
}
This way you will have filled listview with strings from array items.
This is very basic example, you can extend also base adapter, and populate it with your own objects and views.
Here is screenshot with result :
I'm trying to adapt the strategy for hiding / showing a toolbar (or any visual element) from the well explained and great article:
http://mzgreen.github.io/2015/02/15/How-to-hideshow-Toolbar-when-list-is-scroling%28part1%29/
But in my case I'm using a Fragment to hold the recycleview instead of the activity. My problem is that the padding is not being applied so the first element is under the toolbar, and I have also another strange behavior, as the toolbar is also under the statusbar. I don't know what is happening here.
The following are my "moving pieces":
BasicActivity.java: based on the one given on the previous post, but moving away the recycleview part as is going to be on the Fragment piece. Also it exposes the show and hide methods to allow the fragment to access it:
public class BasicActivity extends ActionBarActivity {
private Toolbar mToolbar;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_basic);
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.container,new RecycleFragment())
.commit();
overridePendingTransition(0, 0);
initToolbar();
}
private void initToolbar() {
mToolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(mToolbar);
setTitle(getString(R.string.app_name));
mToolbar.setTitleTextColor(getResources().getColor(android.R.color.white));
}
public void hideViews() {
mToolbar.animate().translationY(-mToolbar.getHeight()).setInterpolator(new AccelerateInterpolator(2));
}
public void showViews() {
mToolbar.animate().translationY(0).setInterpolator(new DecelerateInterpolator(2));
}
}
My activiy_basic.xml is the following:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
<include layout="#layout/toolbar_actionbar" />
</FrameLayout>
The layout toolbar_actionbar.xml
<android.support.v7.widget.Toolbar
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:clipToPadding="false"/>
The Fragment RecycleFragment.java:
public class RecycleFragment extends Fragment {
#Override public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_recycler, container, false);
return view;
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
initRecyclerView(view);
}
private void initRecyclerView(View view) {
RecyclerView recyclerView = (RecyclerView)view.findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
RecyclerAdapter recyclerAdapter = new RecyclerAdapter(createItemList());
recyclerView.setAdapter(recyclerAdapter);
recyclerView.setOnScrollListener(new HidingScrollListener() {
#Override
public void onHide() {
((BasicActivity)getActivity()).hideViews();
}
#Override
public void onShow() {
((BasicActivity)getActivity()).showViews();
}
});
}
private List<String> createItemList() {
List<String> itemList = new ArrayList<>();
for(int i=0;i<20;i++) {
itemList.add("Item "+i);
}
return itemList;
}
}
And the layout for the fragment is just a recyclerview fragment_recycler.xml:
<android.support.v7.widget.RecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
The adapter and the viewholder for the recycler are the same as the article, and they doesn't affect the behavior.
What is wrong with the code?
UPDATE:
A MichaĆ Z. below pointed out. What was missing is the paddingTop and clipptoPadding on the Recyclerview view
So the final xml should be:
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="?attr/actionBarSize"
android:clipToPadding="false"/>
And to solve the statusbar overlapping problem, it is needed to add a "fitsystemwindows" = "true" element on the activity layout. So it must be as the following:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<FrameLayout android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
<include layout="#layout/toolbar_actionbar" />
</FrameLayout>
UPDATE2
The fitSystemWindows is only needed if the theme is setting the statusbar as translucent
Your fragment_recycler.xml file is missing paddingTop and clipToPadding attributes.
It should look like this:
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="?attr/actionBarSize"
android:clipToPadding="false"/>
And also remove clipToPadding from your toolbar_actionbar.xml.