How to disable onTouch of other items in Recyclerview? [duplicate] - java

I am using Floating Action Button. I want to disable Recyclerview Items from Clicking when i press FAB button. I tried this method but not working setClickable(true);
My Layout
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:fab="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="#fff"
tools:context="com.hartwintech.socialchat.activity.IconTabsActivity">
<android.support.v7.widget.RecyclerView
android:id="#+id/recycler_view"
android:scrollbars="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
>
</android.support.v7.widget.RecyclerView>
<com.github.clans.fab.FloatingActionMenu
android:id="#+id/floatmenu"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_marginBottom="60dp"
android:layout_marginRight="16dp"
fab:fab_showAnimation="#anim/show_from_bottom"
fab:fab_hideAnimation="#anim/hide_to_bottom"
fab:menu_labels_style="#style/MenuLabelsStyle"
fab:menu_shadowColor="#444"
fab:menu_colorNormal="#FFB805"
fab:menu_colorPressed="#F2AB00"
fab:menu_colorRipple="#D99200"/>
</RelativeLayout>
Java Class
floatMenu.setOnMenuToggleListener(new FloatingActionMenu.OnMenuToggleListener() {
#Override
public void onMenuToggle(boolean opened) {
if (opened) {
final int color = R.color.transp;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
mrecyclerview.setClickable(false);
mrecyclerview.setEnabled(false);
mrecyclerview.setForeground(new ColorDrawable(ContextCompat.getColor(getContext(), color)));
}
} else {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
mrecyclerview.setClickable(true);
mrecyclerview.setEnabled(true);
mrecyclerview.setForeground(null);
}
}
}
});

You can add a simple boolean to your adapter like this:
public boolean isClickable = true;
and set it in your fab-click:
mAdapter.isClickable = true/false;
And within your OnClickListener in the Adapter, only act when it is clickable:
public void onClick(View view) {
if(!isClickable)
return;
// do your click stuff
}

To disable RecyclerView, follow below steps:
1. Add following view into your layout file,
<View
android:id="#+id/viewDisableLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#40000000"
android:clickable="true"
android:focusable="true"
android:visibility="gone"/>
2. Set View Visibility `View.VISIBLE when you want to disable RecyclerView else

You can simply use recursion to disable/enable clicks on view
public static void setClickable(View view, boolean clickable) {
if (view != null) {
if (view instanceof ViewGroup) {
ViewGroup viewGroup = (ViewGroup) view;
for (int i = 0; i < viewGroup.getChildCount(); i++) {
setClickable(viewGroup.getChildAt(i), clickable);
}
}
view.setClickable(clickable);
}
}

Björn Kechel's answer helps me. As he said I just added Boolean. When i click the fab menu the boolean is activated. Then have to write the condition on mrecyclerview.addOnItemTouchListenerJava Class
public Boolean fabClick = false;
floatMenu.setOnMenuToggleListener(new FloatingActionMenu.OnMenuToggleListener() {
#Override
public void onMenuToggle(boolean opened) {
if (opened) {
final int color = R.color.transp;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
fabClick = true;
mrecyclerview.setClickable(false);
mrecyclerview.setEnabled(false);
mrecyclerview.setForeground(new ColorDrawable(ContextCompat.getColor(getContext(), color)));
}
} else {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
fabClick = false;
mrecyclerview.setClickable(true);
mrecyclerview.setEnabled(true);
mrecyclerview.setForeground(null);
}
}
}
});
mrecyclerview.addOnItemTouchListener(new RecyclerTouchListener(getActivity(), mrecyclerview, new RecyclerTouchListener.ClickListener() {
#Override
public void onClick(View view, int position) {
if(!fabClick) {
android.support.v4.app.FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.setCustomAnimations(R.anim.fragment_anim_start, R.anim.fragment_anim_stop);
Intent i = new Intent(getActivity(), Group_Chat_Screen.class);
startActivity(i);
}
}

You need to set the click listener to every FloatingActionButton.
see this issue on library

Working solution with RecyclerView.OnItemTouchListener:
#SuppressLint("ClickableViewAccessibility")
#BindingAdapter("itemsClickable")
fun setRecyclerViewClickable(view: RecyclerView, clickable: Boolean) {
view.isEnabled = clickable
if (!clickable) {
val itemTouchListener = object : RecyclerView.OnItemTouchListener {
override fun onTouchEvent(rv: RecyclerView?, e: MotionEvent?) {
}
override fun onInterceptTouchEvent(rv: RecyclerView?, e: MotionEvent?): Boolean {
return rv?.isEnabled == false
}
override fun onRequestDisallowInterceptTouchEvent(disallowIntercept: Boolean) {
}
}
view.addOnItemTouchListener(itemTouchListener)
view.tag = itemTouchListener
} else {
(view.tag as? RecyclerView.OnItemTouchListener)?.let {
view.requestDisallowInterceptTouchEvent(true)
view.removeOnItemTouchListener(it)
}
}
}

Java
recyclerView.setOnTouchListener((view1, motionEvent) -> true );
Kotlin
reyclerView.setOnTouchListener { v, event -> true }
this solution disables all touch events

You can disable the touch of recyclerview
recyclerView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
return true;
}
});

In the xml file, set the layout_width and layout_height for FloatingActionMenu as match_parent and set clickable as false :
android:layout_width="match_parent "
android:layout_height="match_parent "
android:clickable="false"
In your java class,
floatMenu.setOnMenuToggleListener(new FloatingActionMenu.OnMenuToggleListener() {
#Override
public void onMenuToggle(boolean opened) {
if (opened) {
floatMenu.setClickable(true);
} else {
floatMenu.setClickable(false);
}
}
});
This should work.

I solved this problem with very simple logic. This will prevent double click on single item and multiple items of RecyclerView as well.
Declare a Variable in your Activity.
private long mLastClickTime = 0;
Then use in any OnClickListener.
#Override
public void onClick(View v) {
if(SystemClock.elapsedRealtime() - mLastClickTime < 1000){//You can reclick after 1 second
return;//Before 1 seconds from first click this onclick will return from here
}
mLastClickTime = SystemClock.elapsedRealtime();
//Do stuff here
}
Actually I found this solution in stackover flow when I was searching for preventing double click on Button. I'm writing this line to acknowledge that actual answer is posted by someone ( Unfortunatly I'm unable to find that answer to link his/her answer here.)
Hope this will solve your problem.:)

Related

Why is my Android ImageView empty (loading up through Uri, Bitmap or using Picasso)

I have a fragment to display a queue of either videos of images. The video I display in the VideoView works fine, it replays, it's golden. But the images I put in the ImageView just appear invisible. I tried loading them through Uri, by reading a Bitmap, now they're set up with Picasso, and none of it fixed it. The AssetObtainer you'll see in MultimediaPlayer works with both sound files and videos so far, so I highly doubt it has an issue with images. Here's the code:
MultimediaPlayer.java :
public class MultimediaPlayer extends Fragment
{
VideoView mVideoView;
ImageView mImageView;
MultimediaViewModel mMultimediaViewModel;
Play mPlayThread;
Activity mActivity;
AssetObtainer assetObtainer = new AssetObtainer();
public Long mTutorialId;
public List<Multimedia> multimedias = new LinkedList<>();
#Override
public View onCreateView(#NotNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
return inflater.inflate(R.layout.fragment_multimedia_player, container, false);
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState)
{
mActivity = requireActivity();
mMultimediaViewModel = new ViewModelProvider(this).get(MultimediaViewModel.class);
mVideoView = view.findViewById(R.id.video_embed);
mImageView = view.findViewById(R.id.image_embed);
getPlayer(0);
}
private void getPlayer(int position)
{
if(mPlayThread != null) {
mPlayThread.interrupt();
position++;
}
if(!multimedias.isEmpty()) {
mPlayThread = new Play(multimedias.get(position));
mPlayThread.start();
}
}
private class Play extends Thread
{
private final Multimedia currentMedia;
Play(Multimedia media){
currentMedia = media;
}
#Override
public void run()
{
int position = currentMedia.getPosition();
int displayTime = currentMedia.getDisplayTime();
boolean loopBool = currentMedia.getLoop();
if(currentMedia.getType()) {
mActivity.runOnUiThread(() -> {
mImageView.setVisibility(View.VISIBLE);
mVideoView.setVisibility(View.GONE);
try {
Picasso.get().load(assetObtainer.getFileFromAssets(requireContext(), currentMedia.getFullFileName())).into(mImageView);
} catch (IOException ignored) {}
});
if(displayTime>0) {
try {
sleep(displayTime);
if(!loopBool) multimedias.remove(currentMedia);
if(position<multimedias.size()-1) {
getPlayer(position);
} else getPlayer(0);
} catch (InterruptedException e) {
mActivity.runOnUiThread(() -> mImageView.setVisibility(View.GONE));
interrupt();
}
}
} else {
mActivity.runOnUiThread(() -> {
mVideoView.setVisibility(View.VISIBLE);
mImageView.setVisibility(View.GONE);
try {
mVideoView.setVideoURI(Uri.fromFile(assetObtainer.getFileFromAssets(requireContext(), currentMedia.getFullFileName())));
} catch (IOException ignored) {}
if(loopBool && multimedias.size()==1) mVideoView.setOnCompletionListener(v->getPlayer(position-1));
mVideoView.start();
});
}
}
}
#Override
public void onPause()
{
if(mPlayThread!=null){
mPlayThread.interrupt();
}
super.onPause();
}
}
bed for the fragment in the activity .xml file :
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/layout_multimedia"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="#id/active_instructions" />
and the .xml file of the fragment :
<androidx.constraintlayout.widget.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:layout_width="match_parent"
android:layout_height="wrap_content"
tools:context=".tutorial.mediaplayer.MultimediaPlayer">
<VideoView
android:id="#+id/video_embed"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="#+id/image_embed"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
android:contentDescription="#string/image_default_no_description" />
</androidx.constraintlayout.widget.ConstraintLayout>
As mentioned, video works super fine, but images won't show. I'd appreciate even monkey wrench suggestions before I have to rework this entirely.
As mentioned in my other answer, it's not related to the ImageView, it's a problem with SQLite and loading a boolean from the database. The default false which I wanted to correspond with video types is default, so it worked, but since it doesn't default to true the image condition wasn't fulfilled. Anyway the ImageView will work once it is actually ran.

Understanding why onClick() is Called Even After onDispatchTouchEvent() Returns True

Lets say, in an Android app, we want to have the ability to temporarily and reliably ignore all user touches at any moment.
From the research I have done on stack-overflow as well as here, here, and here, the agreed-upon solution seems to be something like this:
(Code of MainActivity.java):
// returning true should mean touches are ignored/blocked
#Override
public boolean dispatchTouchEvent(MotionEvent pEvent) {
if (disableTouches) {
return true;
} else {
return super.dispatchTouchEvent(pEvent);
}
}
However, when we introduce the Android Monkey Exerciser Tool and send touch events to the app at a rapid rate, it becomes apparent that pigs begin to fly at the quantum level -- we can get calls to onClick() even after/during times where "blockTouches" has been set to true.
MY QUESTION IS: Why is that? -- Is this a normal Android behavior, or did I make a mistake in my code? :)
Note: I have already ruled out the possibility of onClick() being called by user input other than touches (and therefore being uncontrolled by the onDispatchTouchEvent() method)... by adding "—-pct-touch 100" to the monkey command.
Here is the code I am using for this test:
MainActivity:
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
View rootView; // turns black when "touch rejection" is in progress
View allowedButton;
View notAllowedButton;
// Used to decide whether to process touch events.
// Set true temporarily when notAllowedButton is clicked.
boolean touchRejectionAnimationInProgress = false;
int errorCount = 0; // counting "unexpected/impossible" click calls
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
rootView = findViewById(R.id.rootView);
allowedButton = findViewById(R.id.allowedButton);
notAllowedButton = findViewById(R.id.notAllowedButton);
allowedButton.setOnClickListener(this);
notAllowedButton.setOnClickListener(this);
allowedButton.setBackgroundColor(Color.GREEN);
notAllowedButton.setBackgroundColor(Color.RED);
}
// returning true should mean touches are ignored/blocked
#Override
public boolean dispatchTouchEvent(MotionEvent pEvent) {
if (touchRejectionAnimationInProgress) {
Log.i("XXX", "touch rejected in dispatchTouchevent()");
return true;
} else {
return super.dispatchTouchEvent(pEvent);
}
}
#Override
public void onClick(View viewThatWasClicked){
Log.i("XXX", "onClick() called. View clicked: " + viewThatWasClicked.getTag());
//checking for unexpected/"impossible"(?) calls to this method
if (touchRejectionAnimationInProgress) {
Log.i("XXX!", "IMPOSSIBLE(?) call to onClick() detected.");
errorCount ++;
Log.i("XXX!", "Number of unexpected clicks: " + errorCount);
return;
} // else proceed...
if (viewThatWasClicked == allowedButton) {
// Irrelevant
} else if (viewThatWasClicked == notAllowedButton) {
// user did something that is not allowed.
touchRejectionAnimation();
}
}
// When the user clicks on something "illegal,"
// all user input is ignored temporarily for 200 ms.
// (arbitrary choice of duration, but smaller is better for testing)
private void touchRejectionAnimation() {
Log.i("XXX", "touchRejectionAnimation() called.");
touchRejectionAnimationInProgress = true;
rootView.setBackgroundColor(Color.BLACK);
// for logging/debugging purposes...
final String rejectionID = (new Random().nextInt() % 9999999) + "";
Log.i("XXX", "rejection : " + rejectionID + " started.");
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
try { Thread.sleep(200); } catch (Exception e) {
Log.e("XXX", "exception in touchRejection() BG thread!");
}
runOnUiThread(new Runnable() {
#Override
public void run() {
Log.i("XXX", "rejection " + rejectionID + " ending");
rootView.setBackgroundColor(Color.WHITE);
touchRejectionAnimationInProgress = false;
}
});
}
});
thread.start();
}
}
layout.xml:
<?xml version="1.0" encoding="utf-8"?>
<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/rootView"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<View
android:id="#+id/allowedButton"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="32dp"
android:layout_marginBottom="32dp"
android:tag="allowedButton"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="#+id/notAllowedButton"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<View
android:id="#+id/notAllowedButton"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="32dp"
android:layout_marginBottom="32dp"
android:tag="view2"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#+id/allowedButton"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
If you don't want your onClick() to be triggered on any view click.
Following are the steps which need to take care.
Create custom viewGroup eg: MyConstraintLayout and add all child
inside it.
Override onInterceptTouchEvent(MotionEvent ev) and return it has true.
public class MyConstraintLayout extends ConstraintLayout {
private boolean mIsViewsTouchable;
public ParentView(Context context) {
super(context);
}
public ParentView(Context context, AttributeSet attrs) {
super(context, attrs);
inflate(context, R.layout.custom_view, this);
}
public ParentView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public void setViewsTouchable(boolean isViewTouchable) {
mIsViewsTouchable = isViewTouchable;
}
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return mIsViewsTouchable;
}
}
Note: Use setViewsTouchable() method as per your requirement, If you pass the parameter as true all views are not clickable if false your views will be clickable.

Android CarouselPicker when 1st item is click

I found a library on github that has CarouselPicker com.github.Vatican-Cameos:CarouselPicker:v1.0 i added this in the dependencies and compile also in repositories maven { url 'https://jitpack.io'}
I have successfully make a CarouselPicker this is the JAVA CODE
carouselPicker = (CarouselPicker)findViewById(R.id.carouselPicker);
List<CarouselPicker.PickerItem> itemsImage = new ArrayList<>();
itemsImage.add(new CarouselPicker.DrawableItem(R.drawable.abc));
itemsImage.add(new CarouselPicker.DrawableItem(R.drawable.123));
itemsImage.add(new CarouselPicker.DrawableItem(R.drawable.colors));
itemsImage.add(new CarouselPicker.DrawableItem(R.drawable.shapes));
CarouselPicker.CarouselViewAdapter imageAdapter = new CarouselPicker.CarouselViewAdapter(this, itemsImage,0);
carouselPicker.setAdapter(imageAdapter);
And by having a LinearLayout this is the XML code
<in.goodiebag.carouselpicker.CarouselPicker
android:id="#+id/carouselPicker"
android:layout_marginTop="50dp"
android:layout_marginBottom="20dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:items_visible="three"
/>
I cant find on google on what if the 1st item in the carousel picker selected like a OnClickListenerto change the intent
I found a library you used on this link
You must use addOnPageChangeListener like this:
carouselPicker.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
//position of the selected item
if(position == 0){
startActivity(new Intent(thisActivity.this, anotherActivity1.class));
}
else if(position == 1){
startActivity(new Intent(thisActivity.this, anotherActivity2.class));
}
// Same conditions for another cases.
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
So, your onClickListener that you want to handle the click event, is onPageSelected method.

RecyclerView scrolls one item at a time automatically when switching between the tabs using ViewPager

I have a basic layout setup: DrawerLayout that consists of the main layout for the activity and the layout for the navigation view. The main layout has a CoordinatorLayout and all the necessary ones to implement the collapsing toolbar functionality, as well as a ViewPager which I populate with fragments later on in the code. The fragment's layout mainly consists of the RecyclerView and other minor views.
The problem is the following: whenever I scroll either of the two tabs down a little and swipe to a new tab and return back to the original one, the RecyclerView receives the onScrolled callback (which it shouldn't since I haven't scrolled the RV itself, but the ViewPager) with the negative deltaY parameter (which means the direction is upwards) which causes the next item from the top to come into visibility as a result.
A couple of notes:
The deltaY parameter seems to be always equal to the next item's height from the top (which gives the impression that the RV scrolls one item upwards whenever this whole process happens)
I don't set the OnPageChangeListener to the ViewPager to get notified
whenever the page is scrolled, selected or the state was changed.
I supply the RecyclerViewScrollListener to the fragment's RecyclerView to get notified when the RV has been scrolled to do some logic (like propagating this event to the activity to show or hide the floating action button)
I've made a screenshot of the call stack when the onScrolled is called. Perhaps somebody might find it useful. Take a look.
I've also made a short video representing this behavior. Take a look.
I've checked a lot of resources on the Internet, but none of them helped me to resolve this issue. Feel free to ask any questions. Any help would be much appreciated.
dashboard_activity_layout.xml:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
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/coordinatorLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout
android:id="#+id/appBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:elevation="#dimen/toolbar_shadow_height">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="#dimen/toolbar_height"
android:paddingTop="#dimen/toolbar_padding_top"
app:layout_scrollFlags="scroll|enterAlwaysCollapsed"
app:titleTextAppearance="#style/TitleTextView"
tools:background="#color/colorPrimary"/>
<android.support.design.widget.TabLayout
android:id="#+id/tabLayout"
android:layout_width="match_parent"
android:layout_height="#dimen/dashboard_activity_content_tab_layout_height"
app:tabMode="fixed"
app:tabGravity="fill"
tools:background="#color/colorPrimary"/>
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:id="#+id/viewPager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:overScrollMode="never"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
tools:background="#color/colorPrimaryDark"/>
<android.support.design.widget.FloatingActionButton
android:id="#+id/actionButtonFab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="#dimen/dashboard_activity_content_fab_margin"
android:layout_gravity="bottom|end"
android:src="#mipmap/ic_search_white_24dp"
app:fabSize="normal"
app:useCompatPadding="true"
tools:backgroundTint="#color/colorAccent"/>
DashboardActivity.java (relevant parts):
private void initViewPager() {
mViewPager = findViewById(R.id.viewPager);
mAdapter = new DashboardViewPagerAdapter(getSupportFragmentManager());
mAdapter.setViewPagerId(mViewPager.getId());
mAdapter.setRecyclerViewStateListener(mRecyclerViewStateListener);
populateAdapter();
mViewPager.setAdapter(mAdapter);
mViewPager.setOffscreenPageLimit(mAdapter.getCount());
}
private void populateAdapter() {
BaseFragment baseFragment = mAdapter.getFragmentForPosition(TAB_TAB_1);
if(baseFragment == null) {
baseFragment = SomeFragment.newInstance(Common.SOME_TYPE_1);
}
mAdapter.addFragment(baseFragment);
baseFragment = mAdapter.getFragmentForPosition(TAB_TAB_2);
if(baseFragment == null) {
baseFragment = SomeFragment.newInstance(Common.SOME_TYPE_2);
}
mAdapter.addFragment(baseFragment);
baseFragment = mAdapter.getFragmentForPosition(TAB_TAB_3);
if(baseFragment == null) {
baseFragment = SomeOtherFragment.init();
}
mAdapter.addFragment(baseFragment);
}
private RecyclerViewStateListener mRecyclerViewStateListener = new RecyclerViewStateListener() {
#Override
public void onScrolledDownwards(RecyclerView recyclerView, int deltaY) {
// Hiding the FAB by animating it
DashboardCommon.hideActionButton(mActionButtonFab, mViewAnimator, true);
}
#Override
public void onScrolledUpwards(RecyclerView recyclerView, int deltaY) {
// Showing the FAB by animating it
DashboardCommon.showActionButton(mActionButtonFab, mViewAnimator, true);
}
};
SomeFragment.java (relevant parts):
private void initRecyclerView() {
mRecyclerView = findViewById(R.id.recyclerView);
mRecyclerView.addOnScrollListener(new RecyclerViewScrollListener(this));
mLayoutManager = new LinearLayoutManager(
getContext(),
LinearLayoutManager.VERTICAL,
false
);
mRecyclerView.setLayoutManager(mLayoutManager);
mAdapter = new SomeRecyclerViewAdapter(getContext(), mItems);
mRecyclerView.setAdapter(mAdapter);
}
// mRecyclerViewStateListener is the listener passed from the
// DashboardActivity
#CallSuper
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
if(mRecyclerViewStateListener != null) {
mRecyclerViewStateListener.onScrollStateChanged(recyclerView, newState);
}
}
#Override
public void onScrolled(RecyclerView recyclerView, int deltaX, int deltaY) {
if(mRecyclerViewStateListener != null) {
mRecyclerViewStateListener.onScrolled(recyclerView, deltaX, deltaY);
}
}
#Override
public void onScrolledDownwards(RecyclerView recyclerView, int deltaY) {
if(mRecyclerViewStateListener != null) {
mRecyclerViewStateListener.onScrolledDownwards(recyclerView, deltaY);
}
}
#Override
public void onScrolledUpwards(RecyclerView recyclerView, int deltaY) {
if(mRecyclerViewStateListener != null) {
mRecyclerViewStateListener.onScrolledUpwards(recyclerView, deltaY);
}
}
#Override
public void onBottomReached() {
if(mRecyclerViewStateListener != null) {
mRecyclerViewStateListener.onBottomReached();
}
}
#Override
public void onMidpointReached(int direction) {
if(mRecyclerViewStateListener != null) {
mRecyclerViewStateListener.onMidpointReached(direction);
}
}
#Override
public void onTopReached() {
if(mRecyclerViewStateListener != null) {
mRecyclerViewStateListener.onTopReached();
}
}
RecyclerViewScrollListener.java (relevant parts):
public class RecyclerViewScrollListener extends RecyclerView.OnScrollListener {
public static final int DIRECTION_UNSPECIFIED = -1;
public static final int DIRECTION_UPWARDS = 0;
public static final int DIRECTION_DOWNWARDS = 1;
// Omitted...
private StateListener mStateListener;
public RecyclerViewScrollListener(StateListener stateListener) {
// Omitted..
mStateListener = stateListener;
}
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
if(mStateListener != null) {
mStateListener.onScrollStateChanged(recyclerView, newState);
}
}
#Override
public void onScrolled(RecyclerView recyclerView, int deltaX, int deltaY) {
if(mStateListener != null) {
mStateListener.onScrolled(recyclerView, deltaX, deltaY);
}
f(deltaY > 0) {
// Recycler view's contents are moving downwards
// Notifying about the downwards scroll
if(mStateListener != null) {
mStateListener.onScrolledDownwards(recyclerView, deltaY);
}
// Omitted...
if(someConditionIsTrue) {
// Omitted...
// Notifying the listener
mStateListener.onBottomReached();
} else if((someOtherConditionIsTrue) {
mStateListener.onMidpointReached(DIRECTION_DOWNWARDS);
}
} else if(deltaY < 0) {
// Recycler view's contents are moving upwards
// Notifying about upwards scroll
if(mStateListener != null) {
mStateListener.onScrolledUpwards(recyclerView, deltaY);
}
// Omitted...
if(someConditionIsTrue) {
// Omitted..
// Notifying the listener
mStateListener.onTopReached();
} else if(someOtherConditionIsTrue) {
mStateListener.onMidpointReached(DIRECTION_UPWARDS);
}
}
}
public interface StateListener {
void onScrollStateChanged(RecyclerView recyclerView, int newState);
void onScrolled(RecyclerView recyclerView, int deltaX, int deltaY);
void onScrolledDownwards(RecyclerView recyclerView, int deltaY);
void onScrolledUpwards(RecyclerView recyclerView, int deltaY);
void onBottomReached();
void onMidpointReached(int direction);
void onTopReached();
}
}
Using This Scroll one item at a time automatically
RecyclerView my_recycler_view= (RecyclerView) findViewById(R.id.my_recycler_view);
SnapHelper snapHelper = new PagerSnapHelper();
snapHelper.attachToRecyclerView(my_recycler_view);
Happy Coding Cheers
Hope will help
RecyclerView my_recycler_view= (RecyclerView) findViewById(R.id.my_recycler_view);
SnapHelper snapHelper = new PagerSnapHelper();
snapHelper.attachToRecyclerView(my_recycler_view);
Even though I posted this question more than 2 years ago, I've decided to provide an answer. Better late than never, right?
As far as I remember, the problem was in the fact that the layout of the RecyclerView items had the TextView, which contained android:textIsSelectable="true" attribute. Turned out that by removing that attribute, the problem went away. How did I implement text selection then, you may ask? To be honest, I do not recall since it's been so long ago.
Anyway, if you have a problem like this, try removing the android:textIsSelectable="true" attribute and it may very well fix the issue for you.

Ripple Effect On ImageView not triggering

I have a RecyclerView with ImageViews in each item.
I set onClickListener for the ImageViews in onBindViewHolder as follows:
holder.starIV.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO: logic
}
});
The ripple effect worked fine until I added the following logic to onClick. This logic changes the Drawable for the ImageView.
holder.starIV.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (v.getId() == holder.starIV.getId()) {
ListItem clickedItem = mDataset.get(position);
ListItem updatedItem = new ListItem(clickedItem);
if (clickedItem.getStarState() == STAR_ON) {
updatedItem.setStarState(STAR_OFF);
updatedItem.setStarDrawable(
ContextCompat.getDrawable(
v.getContext(),R.drawable.ic_star_border_24px));
}
else if (clickedItem.getStarState() == STAR_OFF) {
updatedItem.setStarState(STAR_ON);
updatedItem.setStarDrawable(
ContextCompat.getDrawable(
v.getContext(),R.drawable.ic_star_24px));
}
mDataset.set(position,updatedItem);
notifyDataSetChanged();
}
}
});
Now, I get no ripple effect at all. Here's the XML for the ImageView:
<ImageView
android:id="#+id/list_item_star"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:paddingLeft="4dp"
android:paddingRight="16dp"
android:src="#drawable/ic_star_border_24px"
android:clickable="true"
android:background="?attr/selectableItemBackgroundBorderless"
android:drawSelectorOnTop="true"
/>
The ripple effect works normally again when i comment out the logic part in onClick.
Have I implemented the above correctly?
What change would you suggest to get the ripple effect working correctly?
EDIT: It appears that changing the Drawable is interfering with the ripple animation. So i moved all the logic to an AsyncTask with a small delay to allow the animation to finish. This seems to work, but I feel this solution is not elegant. Here's the AsyncTask:
class DoLogix extends AsyncTask<Integer, Integer, Void> {
#Override
protected Void doInBackground(Integer... params) {
try{Thread.sleep(125);}catch (Exception e) {}
publishProgress(params[0]);
return null;
}
protected void onProgressUpdate(Integer... val) {
ListItem clickedItem = mDataset.get(val[0]);
ListItem updatedItem = new ListItem(clickedItem);
if (clickedItem.getStarState() == STAR_ON) {
updatedItem.setStarState(STAR_OFF);
updatedItem.setStarDrawable(starBorder);
}
else if (clickedItem.getStarState() == STAR_OFF) {
updatedItem.setStarState(STAR_ON);
updatedItem.setStarDrawable(star);
}
mDataset.set(val[0],updatedItem);
notifyDataSetChanged();
}
}
u can set a ripple drawable as the foreground of ur imageview.
add below code to your parent layout
android:clickable="true"
android:focusable="true"
android:background="?attr/selectableItemBackgroundBorderless"

Categories