RecyclerView: Disable scrolling caused by change in focus - java

TL;DR I have a RecyclerView of EditTexts. When the user is focused on EditText #1 and taps on EditText #2, I want EditText #2 to get focus but I don't want the ReyclerView to scroll. How can I achieve this?
I'm trying to work with a RecyclerView populated with a bunch of EditTexts. When I'm focused on one EditText and I click on another, the RecyclerView scrolls so that the second is at the top of the screen. I want to disable this auto-scrolling from the RecyclerView, but I still want the user to be able to scroll, and I still want the second EditText to be focused on so the user can start typing. How can I achieve this?
I've already tried the following solutions:
https://stackoverflow.com/a/8101614/4077294, but with a RecyclerView.OnItemTouchListener. I called recyclerView.requestFocusFromTouch in onInterceptTouchEvent.
Behavior: Scrolled to the top of the tapped EditText all the time.
Clearing the focus from any EditText whenever it was focused on, via
editText.setOnFocusChangeListener(new OnFocusChangeListener() {
#Override
public void onFocusChange(View v, bool hasFocus) {
if (hasFocus) {
v.clearFocus();
}
}
});
Behavior: The keyboard never showed up, and the RecyclerView still scrolled to the top.
Disabling scrolling altogether as in this question is not acceptable because I still want the user to be able to scroll.

I ended up with this solution from #pskink:
recylerView.setLayoutManager(new LinearLayoutManager(this) {
#Override
public boolean requestChildRectangleOnScreen(RecyclerView parent, View child, Rect rect, boolean immediate) {
return false;
}
});
It seems to work perfectly, but #pskink has mentioned that this could have problems when using arrow keys. He's posted another solution here: https://pastebin.com/8JLSMkF7. If you have problems with the above solution, you may try the alternative solution at the link. For now, I'm sticking with the one I just posted here.
UPDATE
Since support-library v25.3.0 you should also override another requestChildRectangleOnScreen method in LayoutManager:
#Override
public boolean requestChildRectangleOnScreen(RecyclerView parent, View child, Rect rect, boolean immediate, boolean focusedChildVisible) {
return false;
}

RecyclerView will scroll to focused item.
Try recyclerView.setFocusable(false).
This worked for me.

Related

How Do I Change the onClick() Behavior of a Button?

I'm really not sure where to go with this question because I don't necessarily know how possible it is. I'm still somewhat new to Android Studio and coding overall, but I know enough to be dangerous (perhaps that's my problem - I may be thinking too grandiose for a beginner) but this is what I'm looking to do.
I have a single page app with several buttons. I'm creating an app that is essentially a score counter for an NFL game, and the section where my choices for scoring methods looks as follows:
The above section is a Horizontal LinearLayout with 2 Nested LinearLayouts for the 4 scoring buttons on each side. The vertical toggle buttons are already set to change the text on the bottom button from Fieldgoal to Safety and vice-versa depending on the True/False of the toggle for each side.
teamOneToggleButton.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton compoundButton, boolean isChecked) {
if (isChecked) {
teamTwoToggleButton.setChecked(false);
teamOneSafety.setText("SAFETY");
teamTwoSafety.setText("FIELDGOAL");
} else {
teamTwoToggleButton.setChecked(true);
teamTwoSafety.setText("SAFETY");
teamOneSafety.setText("FIELDGOAL");
} } });
I have that part figured out, but since a Safety scores as 2 points and a fieldgoal scores as 3 points, I need to be able to change the onClick behavior.
I was hoping that there was a Java function that would let me set a new onClick activity much like I can setText, setColor, setAlignment, set(whatever), but I can't find anything close.
I've also played around with trying to define a string based on a .getText() from the button itself, but my application crashes every time.
If anyone has any ideas my full code is here on my Github.
If I understand your question you want to change the OnClickListener.
Currently you define it in your XML:
android:onClick="touchdownClickTeamOne" //This is not recommended practice, now you know.
You should do this in your Java code instead:
Button teamOneTouchDown = findViewById(R.id.team_one_off_td);
teamOneTouchDown.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// Do stuff
}
});
Now you know how to redefine any button's OnClickListener.
I'm not sure how to set it up in a way to programmatically do "this" if the button displays 'Safety' and do "that" if the button displays 'Fieldgoal'.
Currently you use this method:
public void fieldgoalClickTeamOne (View v) {
scoreTeamOne = scoreTeamOne + 3;
displayForTeamOne(scoreTeamOne);
}
We know the View v is a Button and that's Buttons are TextViews, so let's check the text:
public void fieldgoalClickTeamOne (View v) {
TextView textView = (TextView) v; // Could cast to Button, makes no difference here
if (textView.getText().toString().equals("SAFETY") {
// Do this
} else {
// Do that
}
}
PS I'm happy to see a beginner following coding conventions, your code is very easy to read. I have a few pointers.
First you should take a moment to learn the difference between if, else if, and else. Your AdapterView should only have on if statement and many else ifs.
Second you should take some time to learn about generic coding practices and/or reusability (this concept is a little tricky). Back to your AdapterViews, you only need one OnItemSelectedListener:
OnItemSelectedListener onItemSelectedListener = new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
final ImageView imageView;
if (adapterView.getId() == R.id.teamOneSpinner)
imageView = (ImageView) findViewById(R.id.team_one_spinner_team_logo);
else
imageView = (ImageView) findViewById(R.id.team_two_spinner_team_logo);
String s=((TextView)view).getText().toString();
if(s.equals("Arizona Cardinals"))
imageView.setImageResource(R.drawable.arizona_cardinals);
else if(s.equals("Atlanta Falcons"))
imageView.setImageResource(R.drawable.atlanta_falcons));
else if(s.equals("Baltimore Ravens"))
//etc, etc
Viola, one listener for multiple spinners. Set it like so:
teamOneSpinner.setOnItemSelectedListener(onItemSelectedListener);
teamTwoSpinner.setOnItemSelectedListener(onItemSelectedListener);
See how much writing I saved you! Many of your methods are repetitive, you can remove 80% of your code with these techniques.

Enable and Disable look and feel of RecyclerView

I have Recylerview on my Activity.I can disable recylerview items selection using below code
recyclerView.addOnItemTouchListener(new RecyclerView.SimpleOnItemTouchListener() {
#Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
// true: consume touch event
// false: dispatch touch event
return touch;
}
});
But I want below functionality to show disable/enable look and feel
Enabled RV:
on Switching off,Disabled all or some items in RecylerView as below
I guess its kind some transparent view over `RecyclerView' as items are still clickable because I can see ripple effect on items click but functionality not works on disable. how can achieve this behavior in my application
After disabling the recyclerview from above code, change the opacity of each row and setEnable(False) for each row item and while enabling the recyclerview remove the opacity and setEnable(true).
inside the changelistner for toogle button refresh the recyclerview with your changes of opacity and all.
for you information i am adding a simple code:-
toggle.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
if(b){
tvText.setEnabled(true);
tvText.setText("enabled");
tvText.setAlpha(1);
}else{
tvText.setText("disabled");
tvText.setAlpha(0.4f);
tvText.setEnabled(false);
}
}
});
refresh your recyclerview from if else loop and pass the enable/disable values to it and change the each row's alpha.
just add transparent view over recycler view and Set android:clickable="true" in xml to your foreground view.

Horizontal Scroll View working unexpectedly

I am trying to create a calculator. I am working in the latest Android Studio. Like in calculators, all new tokes(numbers, operators) should be shown in the right and if the field is larger than the display, it should scroll to the latest token. I have already browsed and found a way to do the same.
The code for the same is:
private void scrollRight() {
horizontalScrollView = (HorizontalScrollView) findViewById(R.id.horizontalScrollView);
ViewTreeObserver viewTreeObserver = horizontalScrollView.getViewTreeObserver();
viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
horizontalScrollView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
horizontalScrollView.scrollTo(entry.getWidth(), 0);
}
});
}
scrollRight is called by a onClick event which checks if a token is entered and calls this.
Everything is working perfectly, i.e. on every new token the scroll bar is scrolling to the end. But if I try to scroll to the beginning manually, it no longer works. After this every time a new token is pressed, the scroll bar first moves to the end and then back to the beginning.
The only option that remains is to restart the program. I tried debugging the OnGlobalLayout function but the debugger loses all frames while stepping out from the function, so it is difficult to know what exactly is making the scroll bar go to the beginning.
GIF to show the problem:
Please Help!
Try
horizontalScrollView.post(new Runnable() {
#Override
public void run() {
horizontalScrollView.fullScroll(View.FOCUS_RIGHT);
}
});
And call findViewById only once in onCreate.

Android - Scrollable TextView with OnClickListener

I have a scrollable textview with an onClickListener attached to it.
textView.setOnClickListener( new OnClickListener() {
#Override
public void onClick(View v) {
//DoStuff();
}
});
The problem is if I scroll the text, as soon as I lift my finger off the view it triggers the onClickListener. The only way this doesn't happen is if I scroll and then move off the view before I lift my finger, and I can't exactly tell my users to do that :P
So my question is, is there a way to determine between a click and a scroll or is the only way to do this to use an onTouchListener and decide for myself if it was a scroll or a click?
Use onTouchListener and handle ON_DOWN and ON_MOVE instead of using onClick.

make RadioGroup to check button on ACTION_DOWN

i managed to do that by adding "actionDownChecker" on every RadioButton.
private View.OnTouchListener actionDownChecker = new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN){
mTabbar.check(view.getId());
}
return true;
}
};
public void add(int radioButtonResourceId, Class<? extends Fragment> contentClass) {
mContent.put(radioButtonResourceId, new TabInfo(radioButtonResourceId, contentClass));
//hack to check radio button on ACTION_DOWN, not UP!
mTabbar.findViewById(radioButtonResourceId).setOnTouchListener(actionDownChecker);
}
Is there another more elegant way to do that?
The only other way I would know how to do it, is to physically change the code in the Listener. I'm not the smartest guy when it comes to developing for android, but the default constructor sets the boxes attached to RadioButtons to check on release.
Unless someone else knows something I don't, you either have to modify the listener class, or modify the entry after the listener has been evoked (by adding your actionDownCheker). Personally if it was me, i would just copy and paste your actionDownChecker, that way your listener class isn't messed up for your next project.
I'm sure there are some applications for it, but I'm not sure why you would want to do that. If someone presses down on the wrong button, they can just move off the button before it is released to cancel the press.

Categories

Resources