I have a weird issue with my checkboxes in RecyclerView.
When I click once on it everything works perfectly (move and change style) but when I click twice (enough fast) it performs some part of the code (just move it down and uncheck). I want to prevent it but I don't know how.
I tried the solution from here https://stackoverflow.com/a/16514644/10802597 but it makes it even worse (maybe I do it in a wrong way).
Here is my code:
holder.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
int currentPosition = holder.getAdapterPosition();
if(isChecked){
FinalListItem finalItemBefore = finalListItems.get(currentPosition);
FinalListItem finalItemAfter = new FinalListItem(finalItemBefore.getName(), true);
finalListItems.remove(finalItemBefore);
finalListItems.add(finalItemAfter);
recyclerView.scrollToPosition(0);
holder.linearLayout.setBackgroundResource(R.drawable.listitem_green);
notifyItemMoved(currentPosition, getItemCount() - 1);
}
else{
finalListItems.get(currentPosition).setChecked(false);
notifyItemChanged(currentPosition);
}
}
});
You can use this
private long mLastClickTime = 0;
if (SystemClock.elapsedRealtime() - mLastClickTime < 1000) {
return;
}
mLastClickTime = SystemClock.elapsedRealtime();
inside your click and it will prevent another click for 1 sec
but don't use it inside your checkbox method, from what I can see its adapter so set ID for the whole row and put this method on the row click.
Related
Is it possible to check if a ScrollView is scrolled all its way in the top?
I want to check this so I can enable a SwipeRefreshLayout, otherwise keeping it disabled.
With a ListView it could be done like this, but there's no setOnScrollListener for ScrollViews
listView.setOnScrollListener(new OnScrollListener() {
#Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
#Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
boolean enable = false;
if(listView != null && listView.getChildCount() > 0){
// check if the first item of the list is visible
boolean firstItemVisible = listView.getFirstVisiblePosition() == 0;
// check if the top of the first item is visible
boolean topOfFirstItemVisible = listView.getChildAt(0).getTop() == 0;
// enabling or disabling the refresh layout
enable = firstItemVisible && topOfFirstItemVisible;
}
swipeRefreshLayout.setEnabled(enable);
}
});
This link might be helpful to You. It shows, how to set scroll listener for ScrollView. Then, refer to #antonio answer.
For your case it would be:
mScrollView.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
#Override
public void onScrollChanged() {
int scrollY = mScrollView.getScrollY(); //for verticalScrollView
if (scrollY == 0)
swipeRefresh.setEnabled(true);
else
swipeRefresh.setEnabled(false);
}
});
You can use the getScrollY() method (from the View class)
In Kotlin:
scrollView.viewTreeObserver.addOnScrollChangedListener {
if (!scrollView.canScrollVertically(1)) {
// Bottom of scroll view.
}
if (!scrollView.canScrollVertically(-1)) {
// Top of scroll view.
}
}
I have three checkboxes and if any two of them are selected I want to disable the third checkbox immediately. I am not getting how to proceed.
Manage your CheckBoxes in a List, so you can iterate over them.
List<CheckBox> boxes = new ArrayList<>();
Assign them like so (in onCreate() of your activity)
boxes.add((CheckBox) findViewById(R.id.checkbox1));
boxes.add((CheckBox) findViewById(R.id.checkbox2));
boxes.add((CheckBox) findViewById(R.id.checkbox3));
Add an onCheckedChangeListener like this:
for(CheckBox box : boxes){
box.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
manageBoxes();
}
});
}
and finally your manageBoxes()
private void manageBoxes(){
int count = 0;
for(CheckBox box : boxes){
count += box.isChecked()?1:0;
}
if(count>=2){
for(CheckBox box : boxes){
box.setEnabled(box.isChecked());
box.setClickable(box.isChecked()); // not sure if needed
}
}else{
// reset all boxes
for(CheckBox box : boxes){
box.setEnabled(true);
box.setClickable(true);
}
}
}
Just a quick and dirty thought. Hope this works.
Plus: This is scalable, so you could include some more checkboxes if needed.
Try to implement this way :
private ArrayList<Integer> integers = null;
integers = new ArrayList<>();
chkBox.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
try {
int position = (int) yourview.getTag();
if (chkBox.isChecked()) {
integers.add(position);
chkBox.setChecked(true);
} else {
if (integers.size() > 0) {
for (int i=0; i<integers.size(); i++) {
if (integers.get(i) == position) {
integers.remove(i);
}
}
});
if (integers.size() > 2) {
//Disable your third checkbox
}
Add a change handler or a click handler on each of the checkboxes and let it call a small method that is responsible for checking the value of each checkbox: if two of them are true disable the third one.
For example:
checkbox1.setOnCheckedChangeListener(new OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
handleCheckBoxes();
}
});
//Do this for all the checkboxes
private void handleCheckBoxes(){
int checkedCount = 0;
CheckBox uncheckedBox = null;
if(checkBox1.isChecked()){
checkedCount++;
}
else{
uncheckedBox = checkBox1;
}
if(checkBox2.isChecked()){
checkedCount++;
}
else{
uncheckedBox = checkBox2;
}
if(checkBox3.isChecked()){
checkedCount++;
}
else{
uncheckedBox = checkBox3;
}
if(checkedCount == 2){
uncheckedBox .setEnabled(false);
}
else{
//enable all checkboxes
checkBox1.setEnables(true);
checkBox2.setEnables(true);
checkBox3.setEnables(true);
}
In pseudo code this would be:
Create variable to hold the number of checkboxes checked, let's call it amountChecked
When a checkbox gets checked => increment the amountChecked
When a checkbox gets checked => check if the amountChecked is equal or greater than the allowedAmountChecked (in your case this is 2)
=> if it is greater or equal to the allowedAmountChecked then disable the remaining checkboxes
I've tried a hundred different methods to implement a delay between automated button clicks, including thread.sleep, Handler.postDelayed, and so on… It could be I have used it incorrectly somehow. My most recent attempt was with a simple boolean toggle. It seems that no matter how I try, all the buttons that are to be automatically clicked happen at the same time after the delay, INSTEAD of being delayed between clicks.
my code as it stands now:
setting up button onClickListener:
for (int i = 0; i < mDifficulty; i++) {
ButtonsOCLArray[i].setOnClickListener(new OnClickListener() {
public void onClick(final View v) {
animating = true;
while (animating) {
animateButtons(v);
}
}
});
}
animation of buttons:
public static void animateButtons(View v) {
AlphaAnimation fadeInAnimation = new AlphaAnimation(0F, 1F);
fadeInAnimation.setDuration(1500);
fadeInAnimation.setFillAfter(true);
v.startAnimation(fadeInAnimation);
animating = false;
}
and finally, from a separate class, the automatic button setup:
public void pushAiButton(final View [] v){
mWhichButton = (mGameAi.getRandomNumber(MainActivity.mDifficulty)); // get random number for random button to press
mListOfAiButtonsToPress.add(mWhichButton); // add random number to mLOABTP
mListOfAiButtonsTemp.addAll(mListOfAiButtonsToPress); // add all elements of mLOABTP to mLOABT
boolean empty = false;
while (!empty) {
if (empty) {
break;
}
tempArrayIndex = mListOfAiButtonsTemp.get(0); // tempArray given value in first slot of mLOABT
mListOfAiButtonsTemp.remove(mListOfAiButtonsTemp.get(0)); // first slot of MLOABT removed
if (mListOfAiButtonsTemp.isEmpty()) {
// looped through whole list, empty now
empty = true;
} // end if
v[tempArrayIndex].performClick(); // click button at index *button*[*index*]
} // end !empty while
} // end pushAiButton()
any ideas HIGHLY appreciated! thanks!
UPDATE
This got it working:
mButtonStart.setOnClickListener(new OnClickListener() {
#Override
public void onClick(final View v) {
Log.d(TAG, "START BUTTON CLICKED!");
if (firstRun) {
mGameAi.setupAiButtons();
firstRun = false;
}
v.setVisibility(View.INVISIBLE);
animateButtons(ButtonsOCLArray[mGameAi.getFirstButtonInList()]);
mGameAi.deleteFirstButtonInList();
v.postDelayed(new Runnable() {
public void run() {
if (!mGameAi.buttonsListIsEmpty()) {
v.performClick();
}
else {
v.setVisibility(View.VISIBLE);
firstRun = true;
}
}
}, 500);
System.out.println("end of mButtonStart's onclicklistener");
}
});
You have coded it so that they all click nearly simultaneously. The automatic button setup does a "while" loop that iterates through all the buttons - removing them one at a time nearly simultaneously.
In other words, your while loop iterating through the buttons needs to pause (or not queue another click) until the animation is complete.
Here is the problem said another way; when each "onClick" occurs, the boolean "animateButtons" is true and they all enter into the animateButtons method.
You need to have a thread with a wait call on in pushAiButton and wait for each button to finish its animation.
I have a GridView setup and I have implemented the setOnItemClickListener interface. Firstly I have made a little Toast just for feedback and then I moved on to calling my methods. The first method sort of works, I put it into a while loop that will call it until it returns true. The second method, when inserted into the code, prevents the first method from working at all, but I don't get any compiler errors.
Here is my onCreate containing the setOnItemClickListener() with my second method I want to insert commented out:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
GridView gridview = (GridView) findViewById(R.id.gridview);
gridview.setAdapter(new ImageAdapter(this));
final GameplayController gc = new GameplayController(this);
// Create board model, add units to player's list.
final UnitArray gameBoardModel = new UnitArray();
gridview.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View v,
int position, long id) {
Toast.makeText(MainActivity.this, "" + position,
Toast.LENGTH_SHORT).show();
boolean next = false;
while (next == false) {
next = gc.choosePiece(position, gameBoardModel,
(ImageView) v);
}
/*next = false;
while (next == false) {
next = gc.chooseEmpty(position, gameBoardModel,
(ImageView) v);
}*/
}
});
}
I say the first method "kinda" of works because it is a method that will check if the position in the GridView selected is an "allowable" selection and will update the ImageView at that selection and then return true, otherwise it will return false with the idea being that it will loop until the user makes a "valid" selection. Now, if a valid selection is made, it indeed does update the ImageView at the selection accordingly, but when an "invalid" selection is made it simply freezes.
So it "kinda" works, but when I insert my second method, it freezes even if a "valid" selection is made and it never makes it to the second method.
I think there is something I'm missing about the onItemClickListener().
--------------------------EDIT-------------------ADDENDUM--------------
In case it helps to see the first method I'm calling,
public boolean choosePiece(int position, UnitArray ua, ImageView iv) {
if (ua.checkPiece(pNum, position) == true) {
if (ua.checkType(position, "rock")) {
ImageView v = iv;
v.setImageResource(R.drawable.rock1select);
return true;
}
if (ua.checkType(position, "paper")) {
iv.setImageResource(R.drawable.paper1select);
return true;
}
if (ua.checkType(position, "scissors")) {
iv.setImageResource(R.drawable.scissors1select);
return true;
}
}
/*
* With just the IF statements above catching the correct selections, my
* program crashes. I thought simply adding the RETURN FALSE; to catch
* everything else would work since it should just keep looping from the
* mAINaCTIVITY until it hits one of them and RETURNS TRUE;. So I will
* add this ELSE so that it will just redraw what is already there,
* maybe that will fix it? Like, maybe it really really wants to use the
* freaking listener for something.
*
* Nope, that didn't help at all.
*/
else {
System.out.println("Ohhhh, NO YOU DIDN'T!!!");
if (ua.checkType(position, "rock")) {
System.out.println("Bad rock!, BAD!");
ImageView v = iv;
v.setImageResource(R.drawable.rock2);
return false;
}
if (ua.checkType(position, "paper")) {
ImageView v = iv;
v.setImageResource(R.drawable.paper2);
return false;
}
if (ua.checkType(position, "scissors")) {
ImageView v = iv;
v.setImageResource(R.drawable.scissors2);
return false;
}
if (ua.checkType(position, "empty")) {
ImageView v = iv;
v.setImageResource(R.drawable.blank);
return false;
}
}
return false;
}
Maybe there is something here that I have to add to tell the onItemClick.. to move on and stop sending touch events here??
Assuming you know the number of elements that your GameplayController will look through:
boolean found = false;
int size = numberOfElements;
for(int i=0; i<size;i++) {
if(gc.choosePiece(position, gameBoardModel,(ImageView) v)==true) {
found = true;
break;
}
}
if(found) {
// do what u expect
}
You say that when you add some code with a while loop to a method, the method appears to never successfully return. Have you considered that the condition on which this second while loop executes never evaluates to false? (In this case, when value "true" is assigned to variable "next"?)
If you are not sure, maybe you should add a System.out.println() inside each loop that outputs which loop is executing along with the value of "next", most likely it stays false forever or otherwise does not do what you think.
Well my code was so terrible at the point of asking this question, but the immediate problem which cannot be unseen is that I was creating the boolean next INSIDE the onClick, so it was being reset everytime onClick occurred. Moving the creation of boolean next to before the onClick would have fixed the problem.
Sometimes I look at a little tiny problem for too long and can't see anything else but the problem even when the solution is crazy simple.
I've been trying to use selectors in slidingmenu for 2 days without managing to make it work.
Here is what I want to do :
I've a menu which have a ListView in it. I want the selector to point at one particular item and move with the item when the listview is scrolled.
So basically the selector is pointing at the right item but when I'm scrolling, the selector don't move on my phone (android 4.0.4) but it work with the emulator (4.1.2). Do you have any idea of why the menu is not invalidating itself when I ask him to do so ?
/*Setting the sliding menu */
setBehindContentView(R.layout.menu);
setSlidingActionBarEnabled(true);
getSlidingMenu().setMode(SlidingMenu.LEFT);
getSlidingMenu().setTouchModeAbove(SlidingMenu.TOUCHMODE_FULLSCREEN);
getSlidingMenu().setFadeEnabled(true);
getSlidingMenu().setFadeDegree(0.35f);
getSlidingMenu().setShadowWidth(15);
getSlidingMenu().setShadowDrawable(R.drawable.shadow);
getSlidingMenu().setSelectorEnabled(true);
getSlidingMenu().setSelectorDrawable(R.drawable.selector);
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
getSlidingMenu().setBehindWidth((int) (metrics.widthPixels * 0.8));
getSlidingMenu().setSelectedView(null);
/*Creating the content of the sliding menu*/
/*Now we generate the menu below */
maListViewPerso = (ListView) this.findViewById(R.id.listviewperso);
maListViewPerso = SlidingMenuListCreator.getListView(this, (String) this.getTitle(), maListViewPerso, isMissionSelected, isTourneeOpened);
getSlidingMenu().setOnOpenListener(new OnOpenListener() {
#Override
public void onOpen() {
int wantedPosition = 5; // Whatever position you're looking for
int firstPosition = maListViewPerso.getFirstVisiblePosition() - maListViewPerso.getHeaderViewsCount(); int wantedChild = wantedPosition - firstPosition;
if (wantedChild < 0 || wantedChild >= maListViewPerso.getChildCount()) {
} else {
selectedView = maListViewPerso.getChildAt(wantedChild);
}
getSlidingMenu().setSelectedView(selectedView);
getSlidingMenu().invalidate();
}
});
OnTouchListener mOnTouchListener = new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
maListViewPerso.onTouchEvent(event);
int wantedPosition = 5; int firstPosition = maListViewPerso.getFirstVisiblePosition() - maListViewPerso.getHeaderViewsCount(); int wantedChild = wantedPosition - firstPosition;
if (wantedChild < 0 || wantedChild >= maListViewPerso.getChildCount()) {
} else {
selectedView = maListViewPerso.getChildAt(wantedChild); }
getSlidingMenu().setSelectedView(selectedView);
getSlidingMenu().getmViewBehind().invalidate();
return true;
}
};
maListViewPerso.setOnTouchListener(mOnTouchListener);
After all I never find the solution.
But :
I switched to a viewpager navigation mode because that what was users preferred (and discovered that, yes, Fragments are awesome)
Google have finally made this navigation pattern "official" by adding it through the support library and drawerlayout and it works very well for me =)