Hide FloatingActionButton on scroll of RecyclerView - scroll

I want to hide/show FloatingActionButton on scroll of RecyclerView.
My XML layout :
<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent" >
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerview_eventlist"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<android.support.design.widget.FloatingActionButton
android:id="#+id/fab_createevent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="#dimen/fab_margin"
app:layout_anchor="#id/recyclerview_eventlist"
app:layout_anchorGravity="bottom|right|end"
app:layout_behavior="com.eventizon.behavior.ScrollAwareFABBehavior"
android:src="#drawable/ic_edit"
app:backgroundTint="#color/custom_color_1"
app:borderWidth="0dp" />
</android.support.design.widget.CoordinatorLayout>
DrawerLayout is the parent layout of this layout.
public class ScrollAwareFABBehavior extends FloatingActionButton.Behavior {
private static final String TAG = "ScrollAwareFABBehavior";
public ScrollAwareFABBehavior(Context context, AttributeSet attrs) {
super();
Log.e(TAG,"ScrollAwareFABBehavior");
}
#Override
public void onNestedScroll(CoordinatorLayout coordinatorLayout,
FloatingActionButton child, View target, int dxConsumed,
int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
// TODO Auto-generated method stub
super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed,
dxUnconsumed, dyUnconsumed);
Log.e(TAG,"onNestedScroll called");
if (dyConsumed > 0 && child.getVisibility() == View.VISIBLE) {
Log.e(TAG,"child.hide()");
child.hide();
} else if (dyConsumed < 0 && child.getVisibility() != View.VISIBLE) {
Log.e(TAG,"child.show()");
child.show();
}
}
}
Used this layout behaviour for FloatingActionButton.
When I see logcat only constructor is getting called. onNestedScroll() doesn't get called when I scroll the list.

Easiest solution:
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener()
{
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy)
{
if (dy > 0 ||dy<0 && fab.isShown())
{
fab.hide();
}
}
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState)
{
if (newState == RecyclerView.SCROLL_STATE_IDLE)
{
fab.show();
}
super.onScrollStateChanged(recyclerView, newState);
}
});

This should work for you:
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx,int dy){
super.onScrolled(recyclerView, dx, dy);
if (dy >0) {
// Scroll Down
if (fab.isShown()) {
fab.hide();
}
}
else if (dy <0) {
// Scroll Up
if (!fab.isShown()) {
fab.show();
}
}
}
});

Ok, here is what you need:
First, since your FAB depends on the RecyclerView, add the following to your behavior class:
#Override
public boolean layoutDependsOn(CoordinatorLayout parent, FloatingActionButton child, View dependency) {
if(dependency instanceof RecyclerView)
return true;
return false;
}
Next, in order to receive onNestedScroll() calls, you need to override this:
public boolean onStartNestedScroll(CoordinatorLayout parent, FloatingActionButton child, View directTargetChild, View target, int nestedScrollAxes) {
//predict whether you will need to react to the RecyclerView's scroll;
//if yes, return true, otherwise return false to avoid future calls
//of onNestedScroll()
return true;
}
Good luck!
Update
Here is what your ScrollAwareFABBehavior should look like:
public class ScrollAwareFABBehavior extends FloatingActionButton.Behavior {
private static final String TAG = "ScrollAwareFABBehavior";
public ScrollAwareFABBehavior(Context context, AttributeSet attrs) {
super();
}
public boolean onStartNestedScroll(CoordinatorLayout parent, FloatingActionButton child, View directTargetChild, View target, int nestedScrollAxes) {
return true;
}
#Override
public boolean layoutDependsOn(CoordinatorLayout parent, FloatingActionButton child, View dependency) {
if(dependency instanceof RecyclerView)
return true;
return false;
}
#Override
public void onNestedScroll(CoordinatorLayout coordinatorLayout,
FloatingActionButton child, View target, int dxConsumed,
int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
// TODO Auto-generated method stub
super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed,
dxUnconsumed, dyUnconsumed);
if (dyConsumed > 0 && child.getVisibility() == View.VISIBLE) {
child.hide();
} else if (dyConsumed < 0 && child.getVisibility() != View.VISIBLE) {
child.show();
}
}
}
Also, it was tested using com.android.support:design:23.0.1

Short and Simple Solution:
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
if (dy > 0 && mFloatingActionButton.getVisibility() == View.VISIBLE) {
mFloatingActionButton.hide();
} else if (dy < 0 && mFloatingActionButton.getVisibility() !=View.VISIBLE) {
mFloatingActionButton.show();
}
}
});

If you are using Material Components for Android and your FAB is inside a CoordinatorLayout then you can use the layout_behavior com.google.android.material.behavior.HideBottomViewOnScrollBehavior
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="#+id/filter_fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
...
app:layout_behavior="#string/hide_bottom_view_on_scroll_behavior"
... />

If you are not using coordinator layout and want to hide and show FAB smoothly. And you want to implement your own logic to hide fab on scroll down, and show it on scrolling up.
Then here is the solution in kotlin,
Declare a variable,
var scrollingDown = false
After that create a listener,
recycler_view_id.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
if (scrollingDown && dy >= 0) {
scrollingDown = !scrollingDown
id_show_media_fab.startAnimation(
AnimationUtils.loadAnimation(
getApplicationContext(),
R.anim.fab_close
)
)
} else if (!scrollingDown && dy < 0) {
scrollingDown = !scrollingDown
id_show_media_fab.startAnimation(
AnimationUtils.loadAnimation(
getApplicationContext(),
R.anim.fab_open
)
)
}
}
})
create anim resource file
fab_open.xml
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:fillAfter="true">
<scale
android:duration="300"
android:fromXScale="0.0"
android:fromYScale="0.0"
android:interpolator="#android:anim/linear_interpolator"
android:pivotX="50%"
android:pivotY="100%"
android:toXScale="0.9"
android:toYScale="0.9" />
<alpha
android:duration="300"
android:fromAlpha="0.0"
android:interpolator="#android:anim/accelerate_interpolator"
android:toAlpha="1.0" />
</set>
fab_close.xml
just change
android:fromXScale="0.8"
android:fromYScale="0.8"

This is how I did. It works for me! If you don't know how to implement, You can see detail in this link https://guides.codepath.com/android/floating-action-buttons
public class ScrollAwareFABBehavior extends FloatingActionButton.Behavior {
public ScrollAwareFABBehavior(Context context, AttributeSet attributeSet){
super();
}
#Override
public void onNestedScroll(CoordinatorLayout coordinatorLayout, FloatingActionButton child, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed);
if (dyConsumed > 0 && child.getVisibility() == View.VISIBLE) {
child.hide();
} else if (dyConsumed < 0 && child.getVisibility() == View.GONE) {
child.show();
}
}
#Override
public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, FloatingActionButton child, View directTargetChild, View target, int nestedScrollAxes) {
return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL;
}
}

I have created a custom RecyclerView which has OnUpDownScrollListener, OnLeftRightScrollListener ready:
Code:
MBRecyclerView.java
public class MBRecyclerView extends RecyclerView {
private OnScrollListener wrappedUpDownScrollListener;
private OnScrollListener wrappedLeftRightScrollListener;
public MBRecyclerView(Context context) {
super(context);
init();
}
public MBRecyclerView(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
public MBRecyclerView(Context context, #Nullable AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init() {
}
// region Scrolling Listener for Up, Down, Left and Right
public void setOnUpDownScrollListener(final OnUpDownScrollListener onUpDownScrollListener) {
if (wrappedUpDownScrollListener == null) {
wrappedUpDownScrollListener = getWrappedUpDownScrollListener(onUpDownScrollListener);
addOnScrollListener(wrappedUpDownScrollListener);
}
}
public void removeOnUpDownScrollListener() {
if (wrappedUpDownScrollListener != null) {
removeOnScrollListener(wrappedUpDownScrollListener);
wrappedUpDownScrollListener = null;
}
}
public void setLeftOnRightScrollListener(final OnLeftRightScrollListener onLeftRightScrollListener) {
if (wrappedLeftRightScrollListener == null) {
wrappedLeftRightScrollListener = getWrappedLeftRightScrollListener(onLeftRightScrollListener);
addOnScrollListener(wrappedLeftRightScrollListener);
}
}
public void removeOnLeftRightScrollListener() {
if (wrappedLeftRightScrollListener != null) {
removeOnScrollListener(wrappedLeftRightScrollListener);
wrappedLeftRightScrollListener = null;
}
}
private OnScrollListener getWrappedUpDownScrollListener(final OnUpDownScrollListener onUpDownScrollListener) {
return new OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
if (onUpDownScrollListener != null) {
// Negative to check scrolling up, positive to check scrolling down
if (!recyclerView.canScrollVertically(-1)) {
onUpDownScrollListener.onScrolledToTop();
} else if (!recyclerView.canScrollVertically(1)) {
onUpDownScrollListener.onScrolledToBottom();
}
if (dy > 0) {
onUpDownScrollListener.onScrollDown(dy);
} else if (dy < 0) {
onUpDownScrollListener.onScrollUp(dy);
}
}
}
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
if (onUpDownScrollListener != null) {
onUpDownScrollListener.onScrollStopped();
}
}
}
};
}
private OnScrollListener getWrappedLeftRightScrollListener(final OnLeftRightScrollListener onLeftRightScrollListener) {
return new OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
if (onLeftRightScrollListener != null) {
// Negative to check scrolling left, positive to check scrolling right
if (!recyclerView.canScrollHorizontally(-1)) {
onLeftRightScrollListener.onScrolledToMostLeft();
} else if (!recyclerView.canScrollVertically(1)) {
onLeftRightScrollListener.onScrolledToMostRight();
}
if (dy > 0) {
onLeftRightScrollListener.onScrollRight(dx);
} else if (dy < 0) {
onLeftRightScrollListener.onScrollLeft(dx);
}
}
}
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
if (onLeftRightScrollListener != null) {
onLeftRightScrollListener.onScrollStopped();
}
}
}
};
}
public abstract class OnUpDownScrollListener {
public void onScrollUp(int dy) {}
public void onScrollDown(int dy) {}
public void onScrolledToTop() {}
public void onScrolledToBottom() {}
public void onScrollStopped() {}
}
public abstract class OnLeftRightScrollListener {
public void onScrollLeft(int dx) {}
public void onScrollRight(int dx) {}
public void onScrolledToMostRight() {}
public void onScrolledToMostLeft() {}
public void onScrollStopped() {}
}
// endregion
}
Usage (UpDownScrollListener):
mbRecyclerView.setOnUpDownScrollListener(new MBRecyclerView.OnUpDownScrollListener() {
#Override
public void onScrollUp(int dy) {
// show
}
#Override
public void onScrollDown(int dy) {
// hide
}
// aditional functions:
public void onScrolledToTop() {}
public void onScrolledToBottom() {}
public void onScrollStopped() {}
});
similarely you can handle the LeftRight scrolling by setting
setOnLeftRightScrollListener
I hope it can help somebody :)

The solution is in: F.A.B Hides but Doesn't Show
The problem is Android 25.0.x+ sets the view to GONE and thats why the listener is not reporting changes.

All the answers which goes on the Behavior path and onNestedScroll (instead of recyclerview listener) don't comment about the fact that onNestedScroll will be called many times while scrolling. This means that child.show() and child.hide() will be called many times as well. Although show() and hide() are designed to handle that scenario, they still run a lot of code and create some objects which multiplied by the times onNestedScroll is called, result in a lot of objects created unnecessarily.
Considering that and because I wanted to run a different animation instead of the default show() and hide(), I came up with the following Behavior implementation:
public class ScrollAwareFABBehavior extends CoordinatorLayout.Behavior<FloatingActionButton> {
private static final String TAG = "ScrollAwareFABBehavior";
private boolean fabAnimationStarted = false;
private boolean flingHappened = false;
public ScrollAwareFABBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
public boolean onStartNestedScroll(#NonNull CoordinatorLayout coordinatorLayout, #NonNull FloatingActionButton child, #NonNull View directTargetChild, #NonNull View target, int axes, int type) {
if (target instanceof RecyclerView) {
return true;
}
return false;
}
#Override
public void onStopNestedScroll(#NonNull CoordinatorLayout coordinatorLayout, #NonNull final FloatingActionButton child, #NonNull View target, int type) {
super.onStopNestedScroll(coordinatorLayout, child, target, type);
// If animation didn't start, we don't need to care about running the restore animation.
// i.e.: when the user swipes to another tab in a viewpager. The onNestedPreScroll is never called.
if (!fabAnimationStarted) {
return;
}
// Animate back when the fling ended (TYPE_NON_TOUCH)
// or if the user made the touch up (TYPE_TOUCH) but the fling didn't happen.
if (type == ViewCompat.TYPE_NON_TOUCH || (type == ViewCompat.TYPE_TOUCH && !flingHappened)) {
ViewCompat.animate(child).translationY(0).start();
fabAnimationStarted = false;
}
}
#Override
public boolean onNestedFling(#NonNull CoordinatorLayout coordinatorLayout, #NonNull FloatingActionButton child, #NonNull View target, float velocityX, float velocityY, boolean consumed) {
// We got a fling. Flag it.
flingHappened = true;
return false;
}
#Override
public void onNestedPreScroll(#NonNull CoordinatorLayout coordinatorLayout, #NonNull FloatingActionButton child, #NonNull View target, int dx, int dy, #NonNull int[] consumed, int type) {
if (!fabAnimationStarted) {
Log.d(TAG, "onStartNestedScroll: animation is starting");
fabAnimationStarted = true;
flingHappened = false;
CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams) child.getLayoutParams();
ViewCompat.animate(child).translationY(child.getHeight() + lp.bottomMargin).start();
}
}
}

The floating action button will hide when there's scrolling and show when the scrolling stops.
recylerview.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(#NonNull RecyclerView recyclerView, int newState) {
switch (newState) {
case RecyclerView.SCROLL_STATE_IDLE:
addExpenseBtn.show();
break;
default:
addExpenseBtn.hide();
break;
}
super.onScrollStateChanged(recyclerView, newState);
}
});

//lv = ListView
lv.setOnScrollListener(new AbsListView.OnScrollListener() {
#Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
#Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
fab.setVisibility(view.getFirstVisiblePosition() == 0 ? View.VISIBLE : View.INVISIBLE);
}
});

I used this in a RecyclerView.Adapter's onBindViewHolder method to set the bottom margin of the last item in the list to 72dp so that it will scroll up above the floating action button.
This does not require a dummy entry in the list.
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
// other binding code goes here.
if (position + 1 == getItemCount()) {
// set bottom margin to 72dp.
setBottomMargin(holder.itemView, (int) (72 * Resources.getSystem().getDisplayMetrics().density));
} else {
// reset bottom margin back to zero. (your value may be different)
setBottomMargin(holder.itemView, 0);
}
}
public static void setBottomMargin(View view, int bottomMargin) {
if (view.getLayoutParams() instanceof ViewGroup.MarginLayoutParams) {
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) view.getLayoutParams();
params.setMargins(params.leftMargin, params.topMargin, params.rightMargin, bottomMargin);
view.requestLayout();
}
}

A little late, but it works for me.
//This only works on Android M and above
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
recyclerView.setOnScrollChangeListener(new View.OnScrollChangeListener() {
#Override
public void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
if (scrollY > oldScrollY && fab.isShown()) {
fab.hide();
} else if (scrollY < oldScrollY && !fab.isShown()) {
fab.show();
}
}
});
When scrollY is greater than oldScrollY, that means user has scroll down so, we just need to check FAB is showing. If it is, we hide it.
scrollY is less than oldScrollY means a scroll up. We check if FAB is still hidden to show it.

Try this
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
//Customize your if statement
if (recyclerView.computeVerticalScrollOffset() > recyclerView.getHeight() * 2) {
if (!fab.isShown()) {
fab.show();
}
} else {
fab.hide();
}
}
});
enjoy.

Related

LayoutManager for Recyclerview with different cell spancount

I am working to achieve a recycler view interface that looks like this:
Presently, am only using a recyclerview with LinearLayoutManager using an adapter with two viewholders, i tried gridLayout manager too but i did not achieve the target interface: I need help achieving this, Do i have to create a custom Layout Manager? or What exactly do i have to do? Please, I am really stuck on this.
This is my adapter code
public class SimpleStringRecyclerViewAdapter : RecyclerView.Adapter
{
private List<Data> mValues;
private Context context;
private const int TYPE_FULL = 0;
private const int TYPE_HALF = 1;
private const int TYPE_QUARTER = 2;
public SimpleStringRecyclerViewAdapter(Context context, List<Data> items)
{
this.context = context;
mValues = items;
}
public override int ItemCount
{
get
{
return mValues.Count();
}
}
public override void OnBindViewHolder(RecyclerView.ViewHolder holder, int position)
{
if (holder is SimpleViewHolder)
try
{
Data item = mValues.ElementAt(position);
var simpleHolder = holder as SimpleViewHolder;
simpleHolder.mTxtView.Text = Android.Text.Html.FromHtml(item.article.Title).ToString();
simpleHolder.mTxtView2.Text = item.article.Description;
using (var imageView = simpleHolder.mImageView)
{
string url = Android.Text.Html.FromHtml(item.article.UrlToImage).ToString();
//Download and display image
UrlImageViewHelper.SetUrlDrawable(imageView,
url, Resource.Drawable.cheese_1
);
}
// simpleHolder.mprogressbar.Visibility = ViewStates.Gone;
}
catch (Exception e)
{
//Toast.MakeText(this.context, e.ToString(), ToastLength.Long).Show();
}
else
{
try
{
Data item = mValues.ElementAt(position);
var simpleHolder = holder as SimpleViewHolder2;
simpleHolder.mTxtView.Text = Android.Text.Html.FromHtml(item.youTubeItem.Title).ToString();
// simpleHolder.mTxtView2.Text = item.DescriptionShort;
using (var imageView = simpleHolder.mImageView)
{
string url = Android.Text.Html.FromHtml(item.youTubeItem.MaxResThumbnailUrl).ToString();
//Download and display image
UrlImageViewHelper.SetUrlDrawable(imageView,
url, Resource.Drawable.cheese_1
);
}
}
catch (Exception e)
{
//Toast.MakeText(this.context, e.ToString(), ToastLength.Long).Show();
}
}
}
public override int GetItemViewType(int position)
{
if (mValues.ElementAt(position).type == 1)
{
return Resource.Layout.ItemsList;
}
else
{
return Resource.Layout.VideoList;
}
}
public override RecyclerView.ViewHolder OnCreateViewHolder(ViewGroup parent, int viewType)
{
if (viewType == Resource.Layout.ItemsList)
{
View view = LayoutInflater.From(parent.Context).Inflate(Resource.Layout.ItemsList, parent, false);
view.SetBackgroundColor(Color.White);
SimpleViewHolder holder = new SimpleViewHolder(view);
// holder.mprogressbar = view.FindViewById<ProgressBar>(Resource.Id.progressBar);
// holder.mprogressbar.Visibility = ViewStates.Visible;
//Showing loading progressbar
return holder;
}
else
{
View view = LayoutInflater.From(parent.Context).Inflate(Resource.Layout.VideoList, parent, false);
view.SetBackgroundColor(Color.White);
SimpleViewHolder2 holder = new SimpleViewHolder2(view);
return holder;
}
}
}
public class SimpleViewHolder : RecyclerView.ViewHolder
{
public string mBoundString;
public readonly View mView;
public readonly ImageView mImageView;
public readonly TextView mTxtView;
public readonly TextView mTxtView2;
// public ProgressBar mprogressbar;
public SimpleViewHolder(View view) : base(view)
{
mView = view;
mImageView = view.FindViewById<ImageView>(Resource.Id.avatar2);
mTxtView = view.FindViewById<TextView>(Resource.Id.Text11);
mTxtView2 = view.FindViewById<TextView>(Resource.Id.Text12);
// mprogressbar = view.FindViewById<ProgressBar>(Resource.Id.progressBar);
}
public override string ToString()
{
return base.ToString() + " '" + mTxtView.Text;
}
}
public class SimpleViewHolder2 : RecyclerView.ViewHolder
{
public string mBoundString;
public readonly View mView;
public readonly ImageView mImageView;
public readonly TextView mTxtView;
public readonly TextView mTxtView2;
public SimpleViewHolder2(View view) : base(view)
{
mView = view;
mImageView = view.FindViewById<ImageView>(Resource.Id.videoavatar);
mTxtView = view.FindViewById<TextView>(Resource.Id.videoText1);
// mprogressbar = view.FindViewById<ProgressBar>(Resource.Id.progressBar);
}
}
SetUpRecyclerView Method:
dataUse = OfflineDeserializer.OfflineData(content, json2);
recyclerView.SetLayoutManager(new LinearLayoutManager(recyclerView.Context));
recyclerView.SetAdapter(new SimpleStringRecyclerViewAdapter(recyclerView.Context, dataUse));
if (vp.IsShown)
{
vp.Visibility = ViewStates.Invisible;
}
This is what I have presently:
you can use recycler view with multiple view type
here is the link you can refer
Recyclerview with multiple view types
Here is a sample code you can modify it according to your need
public class MyFeedsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
final int
VIDEO = 1,
IMAGE = 2,
AUDIO = 3;
public MyFeedsAdapter(HomeActivity homeActivity, ArrayList<MyFeedsModel> list, MyFeedsFragment myFeedsFragment) {
this.activity = homeActivity;
this.list = list;
this.myFeedsFragment = myFeedsFragment;
metrics = new DisplayMetrics();
activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view;
switch (viewType) {
case VIDEO:
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_myfeeds, parent, false);
return new ViewForVideo(view);
case IMAGE:
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_myfeeds, parent, false);
return new ViewForImage(view);
case AUDIO:
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_myfeeds, parent, false);
return new ViewForAudio(view);
default:
return null;
}
}
#Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) {
if (list.get(position).getFile_type().equals(IntentString.VIDEO)) {
setViewForVideo((ViewForVideo) holder, position);
} else if (list.get(position).getFile_type().equals(IntentString.IMAGE)) {
setViewForImage((ViewForImage) holder, position);
} else if (list.get(position).getFile_type().equals(IntentString.AUDIO)) {
setViewForAudio((ViewForAudio) holder, position);
}
}
#Override
public int getItemCount() {
return list.size();
}
#Override
public int getItemViewType(int position) {
if (list.get(position).getFile_type().equals(IntentString.VIDEO)) {
return VIDEO;
} else if (list.get(position).getFile_type().equals(IntentString.IMAGE)) {
return IMAGE;
} else if (list.get(position).getFile_type().equals(IntentString.AUDIO)) {
return AUDIO;
} else {
return 0;
}
}
public void setViewForVideo(final ViewForVideo holder, final int position) {
}
public void setViewForImage(final ViewForImage holder, final int position) {
}
public void setViewForAudio(final ViewForAudio holder, int position) {
}
public class ViewForVideo extends RecyclerView.ViewHolder {
public ViewForVideo(View itemView) {
super(itemView);
}
}
public class ViewForImage extends RecyclerView.ViewHolder {
public ViewForImage(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
}
public class ViewForAudio extends RecyclerView.ViewHolder {
public ViewForAudio(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
}
}

Trying to pick up a battery. "NullReferenceException" error

Full error is "NullReferenceException: Object reference not set to an instance of an object
battery.OnTriggerStay (UnityEngine.Collider other) (at Assets/battery.cs:32)"
heres my screen in case its something i didnt do in the inspector: http://imgur.com/a/wWSGJ
here is my code (not sure if you need my flashlight code too):
public class battery : MonoBehaviour {
public float a;
public float b;
public float c;
public float d;
public bool showText;
public int Bat;
public GameObject Flight;
public int mainBat;
public bool safeRemove;
void Start()
{
showText = false;
}
void OnTriggerStay(Collider other)
{
showText = true;
if (!safeRemove)
{
if (Input.GetKeyUp (KeyCode.E))
{
mainBat = Flight.GetComponent<flashlight> ().batLevel;
Bat = 20;
Flight.GetComponent<flashlight> ().batLevel = Bat +- mainBat;
safeRemove = true;
if (safeRemove)
{
Destroy (this.gameObject);
}
}
}
}
void OnTriggerExit(Collider other)
{
showText = false;
}
void OnGUI()
{
if (showText)
{
GUI.Box(new Rect(Screen.width/ 2.66f, Screen.height/ 3.48f, Screen.width/ 3.78f, Screen.height/ 16.1f), "Press 'E' to pick up");
}
}
}

Grid view having duplicate column values

I am trying to build a Grid View inside Expandable list view. The problem i am facing is that the the columns in gridview are repeating no matter the number of columns i specify in xml. please find below the code and screen shot. That is there are two child view A and B. Instead of each coming in a single row. A is coming completely on 1st row no matter the number of columns and B is coming on the complete second rows.
ExpandableListAdapter
public class ExpandListAdapter extends BaseExpandableListAdapter {
private Activity activity;
private Context context;
private ArrayList<GroupModel> mMainDatabase;
private LayoutInflater inflater;
private ArrayList<String> parentItems, child, child1, child2;
private CustomGrid adapter;
private GridView grid;
ViewHolder viewHolder;
private static final String LOG_TAG = ExpandListAdapter.class.getSimpleName();
public ExpandListAdapter(ArrayList<GroupModel> mMainDatabase) {
this.mMainDatabase = mMainDatabase;
}
public void setInflater(LayoutInflater inflater, Activity activity) {
this.inflater = inflater;
this.activity = activity;
}
#Override
public int getGroupCount() {
return mMainDatabase.size();
}
#Override
public int getChildrenCount(int groupPosition) {
return mMainDatabase.get(groupPosition).getItemModels().size();
}
#Override
public Object getGroup(int groupPosition) {
return mMainDatabase.get(groupPosition);
}
#Override
public Object getChild(int groupPosition, int childPosition) {
return child.get(childPosition);
}
#Override
public long getGroupId(int groupPosition) {
return groupPosition;
}
#Override
public long getChildId(int groupPosition, int childPosition) {
return childPosition;
}
#Override
public boolean hasStableIds() {
return false;
}
#Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
View v = convertView;
// if (convertView == null) {
// inflate the adapter_side
LayoutInflater vi = (LayoutInflater) activity
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.fragment_list_item, null);
// well set up the ViewHolder
viewHolder = new ViewHolder();
viewHolder.title = (TextView) v.findViewById(R.id.item_title);
viewHolder.image = (ImageView) v.findViewById(R.id.item_image);
viewHolder.image.setId(groupPosition);
if (mMainDatabase.get(groupPosition).getGroupImage() != null &&
!mMainDatabase.get(groupPosition).getGroupImage().equals(""))
Utilities.displayImage(activity.getApplicationContext(), mMainDatabase.get(groupPosition).getGroupImage(), viewHolder.image);
else
Picasso.with(activity).load("http://www.google.com")
.into(viewHolder.image);
viewHolder.title
.setText(mMainDatabase.get(groupPosition).getGroupName());
viewHolder.arrowExpand = (ImageView) v.findViewById(R.id.arrowExpand);
if (isExpanded)
viewHolder.arrowExpand.setImageResource(R.drawable.dropdown2);
else
viewHolder.arrowExpand.setImageResource(R.drawable.dropdown);
return v;
}
#Override
public View getChildView(final int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
if (convertView == null) {
// LayoutInflater infalInflater = (LayoutInflater) context.getSystemService(context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.grid_view, null);
}
grid = (GridView) convertView.findViewById(R.id.grid);
adapter = new CustomGrid(activity, groupPosition, childPosition,activity, mMainDatabase);
grid.setAdapter(adapter);
grid.setTag(childPosition);
grid.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Intent intent = new Intent(activity, FoodDetailActivity.class);
intent.putExtra("item", mMainDatabase.get(groupPosition).getItemModels().
get(Integer.parseInt(view.getTag().toString())));
intent.putExtra("grpId", mMainDatabase.get(groupPosition).get_id());
intent.putExtra("atBottom", true);
activity.startActivity(intent);
}
});
return convertView;
}
#Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}
#TargetApi(Build.VERSION_CODES.JELLY_BEAN)
#Override
public void onGroupExpanded(int groupPosition) {
super.onGroupExpanded(groupPosition);
}
#SuppressLint("NewApi")
#Override
public void onGroupCollapsed(int groupPosition) {
super.onGroupCollapsed(groupPosition);
// ImageView img_selection = (ImageView) groupPosition
// .findViewById(R.id.arrowExpand);
}
static class ViewHolder {
TextView title;
TextView number;
TextView numbertxt;
ImageView image, arrowExpand;
Bitmap b;
int position;
}
}
Custom Grid Adapter
public class CustomGrid extends BaseAdapter {
private Context mContext;
private ArrayList<String> mItemName = null;
private ArrayList<String> mItemImage = null;
private int groupPosition, childPosition;
Activity activity;
ArrayList<GroupModel> mMainDatabase;
LayoutInflater inflater;
public CustomGrid(Context c,
int groupPosition, int childPosition, Activity activity, ArrayList<GroupModel> mMainDatabase) {
mContext = c;
this.groupPosition = groupPosition;
this.childPosition = childPosition;
this.activity = activity;
this.mMainDatabase = mMainDatabase;
}
#Override
public int getCount() {
// TODO Auto-generated method stub
return mMainDatabase.get(groupPosition).getItemModels().size();
}
#Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return null;
}
#Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
View grid;
LayoutInflater inflater = (LayoutInflater) mContext
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if (convertView == null) {
grid = new View(mContext);
grid = inflater.inflate(R.layout.grid_single, null);
TextView textView = (TextView) grid.findViewById(R.id.grid_text);
ImageView imageView = (ImageView)grid.findViewById(R.id.grid_image);
textView.setText(mMainDatabase.get(groupPosition).getItemModels()
.get(childPosition).getItemName());
Log.d("CUSTOMGRID", "child name is " + mMainDatabase.get(groupPosition).getItemModels()
.get(childPosition).getItemName() + " child position is " + childPosition);
if (mMainDatabase.get(groupPosition).getItemModels().get(childPosition).getItemImage() != null &&
!mMainDatabase.get(groupPosition).getItemModels().get(childPosition).getItemImage()
.equals(""))
Picasso.with(activity)
.load(mMainDatabase.get(groupPosition).getItemModels()
.get(childPosition).getItemImage())
.placeholder(R.drawable.place).into(imageView);
else
Picasso.with(activity).load("http://www.google.com")
.placeholder(R.drawable.place).into(imageView);
} else {
grid = (View) convertView;
}
return grid;
}
}

Error null exception in "for" construct xamarin android. Where is incorrect?

This method returns the number of types of Views that will be created by getView method.
public class CustomAdapter : BaseAdapter{
private const int TYPE_ITEM = 0;
private const int TYPE_SEPARATOR = 1;
private List<string> mData;
private TreeSet sectionHeader;
private LayoutInflater mInflater;
public CustomAdapter(Context context, List<string> Data) {
mInflater = (LayoutInflater) context
.GetSystemService(Context.LayoutInflaterService);
this.mData=Data;
}
public void addItem(string item) {
mData.Add(item);
NotifyDataSetChanged();
}
public void addSectionHeaderItem(string item) {
mData.Add(item);
//sectionHeader.Add(mData.Count - 1);
NotifyDataSetChanged();
}
public int getItemViewType(int position) {
return sectionHeader.Contains(position) ? TYPE_SEPARATOR : TYPE_ITEM;
}
public int getViewTypeCount {
get{ return 2; }
}
public override int Count {
get {return mData.Count;}
}
public override Java.Lang.Object GetItem(int position) {
return mData[position];
}
public override long GetItemId(int position) {
return position;
}
public override View GetView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
int rowType = getItemViewType(position);
if (convertView == null) {
holder = new ViewHolder();
switch (rowType) {
case TYPE_ITEM:
convertView = mInflater.Inflate(Resource.Layout.textViewItemsSeparator, parent);
holder.textView = (TextView) convertView.FindViewById(Resource.Id.textviewHeaderItems);
break;
case TYPE_SEPARATOR:
convertView = mInflater.Inflate(Resource.Layout.textViewHeaderItems, parent);
holder.textView = (TextView) convertView.FindViewById(Resource.Id.textviewItemsSeparator);
break;
}
convertView.Tag=holder;
} else {
holder = (ViewHolder)convertView.Tag as ViewHolder;
}
holder.textView.Text=mData[position];
return convertView;
}
public class ViewHolder:Java.Lang.Object {
public TextView textView;
}
}
ListView lst;
string[] items = new string[] { "Alternative Rock","Classical",...........};
List<string> listItems;
private CustomAdapter mAdapter;
public override void OnCreate (Bundle savedInstanceState)
{
base.OnCreate (savedInstanceState);
// Create your fragment here
}
public override View OnCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
// Use this to return your custom view for this Fragment
// return inflater.Inflate(Resource.Layout.YourFragment, container, false);
listItems = new List<string> (items);
return inflater.Inflate (Resource.Layout.GenerFragment, container, false);
}
public override void OnActivityCreated(Bundle savedInstanceState)
{
base.OnActivityCreated(savedInstanceState);
lst = View.FindViewById<ListView> (Resource.Id.lstGenres);
//lst.Adapter = new ArrayAdapter<string>(Activity, Resource.Layout.textViewHeaderItems,Resource.Id.textviewHeaderItems, items);
//lst = View.FindViewById<ListView> (Resource.Id.lst_genre);
//lst.SetAdapter(new ArrayAdapter<String>(this.Activity, Resource.Layout.GenerFragment, items));
//mAdapter=new CustomAdapter();
for (int i = 0; i < listItems.Count(); i++) {
mAdapter.addItem (listItems[i]);
if (i == 0) {
mAdapter.addSectionHeaderItem ("Music");
} else if(i==13) {
mAdapter.addSectionHeaderItem ("Audio");
}
}
lst.Adapter = new CustomAdapter (Activity, listItems);
I spent much time for looking for errors but I have no idea why It was null. although It got a data from list
mAdapter.addItem (listItems[i]); -> null exception when I debug on device. Where is incorrect?
in OnActivityCreated you are referencing listItems
for (int i = 0; i < listItems.Count(); i++) {
however, listItems is null. You initialize it in OnCreateView, which has not been executed yet. You need to be sure that listItems is initialized before you attempt to reference it.
Additionally, you are attempting to add items to mAdapter, but it's never been initialized (as far as I can see)
you declare it here, but it will be NULL until you initalize it
private CustomAdapter mAdapter;
here is the initialization, which is commented out
//mAdapter=new CustomAdapter();
when you attempt to reference it here, it is still null, and will throw a Null Reference Exception
mAdapter.addItem (listItems[i]);

Recycler View with Header and Edit Text

I have a recyclerview with a header achieved by using two different element types. In my header there is an edit text which I want to use for filtering the nonheader elements of the list. Below is my current implementation, I have one concern and one problem with it.
My concern is that what I am doing in publishResults with the notifyItemRangeRemoved and notifyItemInserted is the wrong way to update the recycler view. I originally was doing notifyDatasetChanged but his would cause the header row to be refreshed too and the edit text to lose focus. What I really want is a way to refresh only the item rows and leave the header row untouched.
My current problem is that with the existing code if I scroll down too much the edit text looses focus. I want the edit text to keep focus even if I scroll to the bottom of the list.
The code used to use a ListView with setHeaderView and that worked somehow so there must be someway of achieving the goal just not sure what the trick with a recycler view is. Any help is much appreciated.
public class SideListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> implements Filterable {
private static final int TYPE_HEADER = 0;
private static final int TYPE_ITEM = 1;
private final List<String> data;
public List<String> filteredData;
private HeaderActionListener headerActionListener;
public SideListAdapter(Context context, ArrayList<String> data, HeaderActionListener headerActionListener) {
this.data = data;
filteredData = new ArrayList<>(data);
this.context = context;
this.headerActionListener = headerActionListener;
}
#Override
public Filter getFilter() {
return new TestFilter();
}
static class SideListItem extends RecyclerView.ViewHolder {
LinearLayout baseLayout;
public SideListItem(View itemView) {
super(itemView);
baseLayout = (LinearLayout) itemView.findViewById(R.id.settings_defaultcolor);
}
}
class SideListHeader extends SideListHeader {
EditText sort;
public SideListHeaderLoggedIn(View itemView) {
super(itemView);
sort = (EditText) itemView.findViewById(R.id.sort);
}
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == TYPE_ITEM) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item, parent, false);
return new SideListItem(v);
} else if (viewType == SideListHeader) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.header, parent, false);
return new SideListHeader(v);
}
throw new RuntimeException("there is no type that matches the type " + viewType + " + make sure your using types correctly");
}
public interface HeaderActionListener {
boolean onSortEditorAction(TextView arg0, int arg1, KeyEvent arg2);
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
if (holder instanceof SideListHeader) {
final SideListHeader sideListHeader = (SideListHeader) holder;
sideListHeader.sort.setOnEditorActionListener(new TextView.OnEditorActionListener() {
#Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
}
});
sideListHeader.sort.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) {
}
#Override
public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) {
}
#Override
public void afterTextChanged(Editable editable) {
String result = sideListHeader.sort.getText().toString().replaceAll(" ", "");
getFilter().filter(result);
}
});
}
if (holder instanceof SideListItem) {
// Inflate normal item //
}
}
// need to override this method
#Override
public int getItemViewType(int position) {
if (isPositionHeader(position)) {
return TYPE_HEADER;
}
return TYPE_ITEM;
}
private boolean isPositionHeader(int position) {
return position == 0;
}
//increasing getItemcount to 1. This will be the row of header.
#Override
public int getItemCount() {
return filteredData.size() + 1;
}
private class TestFilter extends Filter {
#Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults results = new FilterResults();
String prefix = constraint.toString().toLowerCase();
if (prefix.isEmpty()) {
ArrayList<String> list = new ArrayList<>(data);
results.values = list;
results.count = list.size();
} else {
final ArrayList<String> list = new ArrayList<>(data);
final ArrayList<String> nlist = new ArrayList<>();
for (int i = 0 ; i < list.size(); i++) {
String item = list.get(i);
if (item.contains(prefix)) {
nlist.add(item);
}
}
results.values = nlist;
results.count = nlist.size();
}
return results;
}
#SuppressWarnings("unchecked")
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
notifyItemRangeRemoved(1, getItemCount()-1);
filteredData.clear();
filteredData.addAll((List<String>)results.values);
for(int i = 1; i < getItemCount() - 1; i++){
notifyItemInserted(i);
}
}
}
}
I'm not sure how correct this way is, but in my code I implemented it like that
private var headerList: List<HeaderItem> = listOf(HeaderItem("Title"))
private fun searchItem(items: List<Items>, query: String) {
items.filterIsInstance<MainItem>().filter { filteredItems ->
filteredItems.header.lowercase().contains(query.lowercase())
}.let { searchedItems ->
rvAdapter.submitList(headerList + searchedItems)
}
}
This way I was able to preserve header element when I did my search

Resources