I want to disable recyclerview scrolling in landscape mode and enable it in the portrait mode.
recyclerView.addOnItemTouchListener(new RecyclerView.SimpleOnItemTouchListener() {
#Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
// Stop only scrolling.
return rv.getScrollState() == RecyclerView.SCROLL_STATE_DRAGGING;
}
});
I am using this method to disable scrolling but can't find a way to enable it again.
Thanks for any help!
You have to get it done using a custom RecyclerView. Initialize it programmatically when the user is in landscape mode and add this view to your layout:
public class MyRecycler extends RecyclerView {
private boolean verticleScrollingEnabled = true;
public void enableVersticleScroll (boolean enabled) {
verticleScrollingEnabled = enabled;
}
public boolean isVerticleScrollingEnabled() {
return verticleScrollingEnabled;
}
#Override
public int computeVerticalScrollRange() {
if (isVerticleScrollingEnabled())
return super.computeVerticalScrollRange();
return 0;
}
#Override
public boolean onInterceptTouchEvent(MotionEvent e) {
if(isVerticleScrollingEnabled())
return super.onInterceptTouchEvent(e);
return false;
}
public MyRecycler(Context context) {
super(context);
}
public MyRecycler(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
}
public MyRecycler(Context context, #Nullable AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
}
For portrait mode keep using your normal RecyclerView.
For this issue, I use this one line solution! :)
myRecyclerView.isNestedScrollingEnabled = false
Related
I would like to disable sound effects when browsing over RecycleView items and also clicking sounds in an Android TV app. But, I do not want to disable all other sounds (e.g., There is Exoplayer in the app that its output sounds should not be muted).
I noticed there are some other questions similar to this on Stackoverflow and the suggested solutions are:
Disable Sound effect in the Layout Files by setting android:soundEffectsEnabled="false" (I put this in every Layout). However, this does not have any effect and there is still clicking and item browsing sound effects.
Disable sound effects using AudioManager. I tried the following:
audioManager.adjustStreamVolume(AudioManager.STREAM_NOTIFICATION, AudioManager.ADJUST_MUTE, 0); and audioManager.adjustStreamVolume(AudioManager.STREAM_SYSTEM, AudioManager.ADJUST_MUTE, 0); These mute all app sounds including Media sounds.
I would be grateful if someone can help with this issue. Thanks
Finally I found a solution for this problem.
Issue 1: Disabling sound effect on pressing DPAD_CENTER key. I could resolve this issue by programmatically disabling sound effect in CardPresenter (for Leanback ListRowPresenter) and CardAdapter (for RecyclerView).
Issue 2: Disabling sound effect on pressing DPAD navigation keys (DPAD_RIGHT, DPAD_LEFT, ...). Digging into the ViewRootImpl.java class, it turns out that navigation sound is always played without checking the soundEffect flag. Here is parts of the code in ViewRootImpl.java
if (v.requestFocus(direction, mTempRect)) {
boolean isFastScrolling = event.getRepeatCount() > 0;
playSoundEffect(
SoundEffectConstants.getConstantForFocusDirection(direction,
isFastScrolling));
return true;
So a workaround that I came up with is to override the requestFocus method in my views and always return false to prevent playing sound effect.
Code for Leanback ListRowPresenter:
CardPresenter.java
public class CardPresenter extends Presenter {
....
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent) {
....
Context mContext = parent.getContext();
CustomImageCardView mCardView = new CustomImageCardView(mContext);
mCardView.setSoundEffectsEnabled(false);
return new ViewHolder(mCardView);
}
CustomImageCardView.java
public class CustomImageCardView extends ImageCardView {
public CustomImageCardView(Context context, int themeResId) {
super(context, themeResId);
}
public CustomImageCardView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public CustomImageCardView(Context context) {
super(context);
}
public CustomImageCardView(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
public boolean requestFocus(int direction, Rect previouslyFocusedRect) {
super.requestFocus(direction, previouslyFocusedRect);
return false;
}
}
Code for RecyclerView:
CardAdapter.java
public class CardAdapter extends RecyclerView.Adapter<CardAdapter.ViewHolder> {
...
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
View view = mLayoutInflater.inflate(R.layout.recycler_view, viewGroup, false);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
view.setFocusable(true);
view.setSoundEffectsEnabled(false);
}
mViewHolder = new ViewHolder(view);
return mViewHolder;
}
CustomLinearLayout.java (Root View for Recycler View)
public class CustomLinearLayout extends LinearLayout {
public CustomLinearLayout(Context context) {
super(context);
}
public CustomLinearLayout(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
}
public CustomLinearLayout(Context context, #Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public CustomLinearLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
#Override
public void playSoundEffect(int soundConstant) {
super.playSoundEffect(soundConstant);
}
#Override
public boolean requestFocus(int direction, Rect previouslyFocusedRect) {
super.requestFocus(direction, previouslyFocusedRect);
return false;
}
}
If you just want to mute android tv navigation system sound effect and there is no custom navigation behavior, I found a way by overriding onKeyDown.
First, I added a GlobalFocusChangeListener at Activity and Dialog to listen and keep the reference of focused view.
window.decorView.viewTreeObserver.addOnGlobalFocusChangeListener { oldFocus, newFocus ->
focusView = newFocus
}
Second, I overrided onKeyDown method at Activity and Dialog and implement like this.
override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {
focusView?.let {
when (keyCode) {
KeyEvent.KEYCODE_DPAD_UP -> View.FOCUS_UP
KeyEvent.KEYCODE_DPAD_DOWN -> View.FOCUS_DOWN
KeyEvent.KEYCODE_DPAD_LEFT -> View.FOCUS_LEFT
KeyEvent.KEYCODE_DPAD_RIGHT -> View.FOCUS_RIGHT
else -> null
}?.let { direction ->
val nextFocusView = it.focusSearch(direction)
if (nextFocusView != null) {
nextFocusView.requestFocus()
return true
}
}
}
return super.onKeyDown(keyCode, event)
}
This is work on android tv emulator and my Xiaomi TV. I think this change will not effect any touch behavior on phone or tablet.
I am trying to select all text when double tapping on an EditText (not on the text itself but on the white space outside the text) by creating a GestureDetector and listener and in onDoubleTap perform the selecteAll.
Unfortunately, just after all text gets selected, the text gets de-selected.
How can I select all text when double tap on the EditText white space?
Thanks!
Custom EditText:
public class TextEditText : EditText, View.IOnTouchListener
{
GestureDetector gestureDetector;
public TextEditText(Context context) : base(context)
{
Init();
}
public TextEditText(Context context, IAttributeSet attrs) :
base(context, attrs)
{
Init();
}
public TextEditText(Context context, IAttributeSet attrs, int defStyle) :
base(context, attrs, defStyle)
{
Init();
}
public TextEditText(IntPtr a, Android.Runtime.JniHandleOwnership b) : base(a, b)
{
Init();
}
void Init()
{
gestureDetector = new GestureDetector(new SelectTextDoubleTapListener(this));
SetOnTouchListener(this);
}
public bool OnTouch(View v, MotionEvent e)
{
return gestureDetector.OnTouchEvent(e);
}
}
then the listener:
public class SelectTextDoubleTapListener : GestureDetector.SimpleOnGestureListener
{
EditText editText;
public SelectTextDoubleTapListener(EditText et)
{
editText = et;
}
public override bool OnDoubleTap(MotionEvent e)
{
if (editText.Text.Length > 0)
{
editText.SetSelection(editText.Text.Length);
editText.SelectAll();
}
return false; // return true does not work either
}
}
Unfortunately, just after all text gets selected, the text gets de-selected.
I solve this by use SetSelectAllOnFocus(true) in the OnDoubleTap
For example:
public override bool OnDoubleTap(MotionEvent e)
{
if (editText.Text.Length > 0)
{
editText.SetSelectAllOnFocus(true);
editText.ClearFocus();
}
return true;
}
In some cases, we need to make the RecyclerView cannot scroll, so play to your strengths for this questions.
I have some solutions for this problem, hope it can help you.See below for details:
void setLayoutFrozen (boolean frozen);
I strongly recommend if we only want to inhabit scroll for this scheme for its simplicity and convenience; if you want to know deeply
When we use LayoutManager(LinearManager or GridLayoutManager), we can use this.
`
LinearLayoutManager linearLayoutManager = new
LinearLayoutManager(mContext, LinearLayoutManager.VERTICAL, false){
#Override
public boolean canScrollVertically() {
return false;
}
#Override
public boolean canScrollHorizontally() {
return super.canScrollHorizontally();
}
};`
GridLayoutManager is alike.
From above second item, we can extend corresponding LayoutManager.
`
public class MyGridLayoutManager extends GridLayoutManager {
private boolean isScrollEnabled = true;
public MyGridLayoutManager(Context context, int spanCount) {
super(context, spanCount);
}
public MyGridLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
public MyGridLayoutManager(Context context, int spanCount, int orientation, boolean reverseLayout) {
super(context, spanCount, orientation, reverseLayout);
}
public void setScrollEnabled(boolean flag) {
this.isScrollEnabled = flag;
}
#Override
public boolean canScrollVertically() {
return isScrollEnabled && super.canScrollVertically();
}
}
`
4. We can handle the RecyclerView TouchEvent to achieve the effect.
From above, I believe you can make yourself. Good Luck...
I'm creating a slot machine application and for this I'm using RecycleView as a rail. Therefore all touch\click\scroll events are disabled for RecyclerView.
And to make "spin" I used RecyclerView.fling(...) method since it has better animation.
BUT appearantly fling stops when I touch the recycler view. Why? And how can I disable this?
xml:
<android.support.v7.widget.RecyclerView
android:id="#+id/rv_rail"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="#dimen/margin_4"
android:layout_marginStart="#dimen/margin_4"
android:layout_weight="1"
android:padding="#dimen/dp_16"/>
init of RecyclerView:
LinearLayoutManager mRailLayoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
mRailsBinding.rvRail.setHasFixedSize(true);
new LinearSnapHelper().attachToRecyclerView(mRailsBinding.rvRail);
mRailsBinding.rvRail.setLayoutManager(mRailLayoutManager);
mRailsBinding.rvRail.addOnItemTouchListener(new RecyclerViewDisabler());
mRailsBinding.rvRail.addOnScrollListener(railScrollListener); //checking here for time when scroll ended
mRailsBinding.rvRail.setAdapter(mRailAdapter);
Adapter does nothing special. It just inits views and has no click\touch evenets on them.
RecyclerViewDisabler:
public class RecyclerViewDisabler implements RecyclerView.OnItemTouchListener {
#Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
return true;
}
#Override
public void onTouchEvent(RecyclerView rv, MotionEvent e) {}
#Override
public void onRequestDisallowInterceptTouchEvent(boolean state) {}
}
Just read documentation carefull and found solution. I was needed to consume dispatchTouchEvenet manually. See code:
public class UntouchableRecyclerView extends RecyclerView {
public UntouchableRecyclerView(Context context) {
super(context);
}
public UntouchableRecyclerView(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
}
public UntouchableRecyclerView(Context context, #Nullable AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
public boolean dispatchTouchEvent(MotionEvent ev) {
return true; //consume
}
}
in my application I have a flipView using the emilsjolander library. It's great, but I can't stop automatically the flipping effect when I open the FlipView. Infact, if I touch the screen the effect stop, but I would stop it after some seconds. Do you know if the library contain a method for it or, alternatively, for simulate the touchEvent after some seconds?
Thank's
I know the answer is so late but it will help others if they stuck in that issue. You can disable automatic flipping on first page by just commenting:
//peakNext(false);
public class MyFlipView extends se.emilsjolander.flipview.FlipView
{
private boolean isEnabled = true;
public MyFlipView(Context context)
{
super(context);
}
public MyFlipView(Context context, AttributeSet attrs)
{
super(context, attrs, 0);
}
public MyFlipView(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
}
#Override
public boolean onInterceptTouchEvent(MotionEvent ev)
{
if (isEnabled)
return super.onInterceptTouchEvent(ev);
else
return false;
}
public void disable()
{
isEnabled = false;
}
public void enable()
{
isEnabled = true;
}
}
Declare xml as
<"YourPackage".MyFlipView
/>