Viewpager but not responding to clicklistener/ - java

I have a bug which I kind of know what is going on but not sure hoo to solve it.
I have a viewpager where each individual fragment also contains two more fragment -- a front side and a back side. The app is basically a flashcard app where you can swipe for the next card and when you click it it turns to the other side.
My problem:
I have a set of radiobuttons available on both sides. If the user checks a button and clicks on the card, the card should turn, and the newly chosen radio button choice should appear on the other side of the card as well. The functionality of the buttons on both sides are the same-- i just put it on both sides so that the user can choose to change the radiobuttons no matter if he/she is on the front side or the back side of the flashcard. The part where the radiobuttons change on the other side if you pick a radiobutton only works when each card is fresh. If you scroll off the offscreenlimit and swipe back, the function does not work anymore(the radiobuttons on the other side won't automatically change to the newly selected one) . But since my offscreenlimit is 2, if you scroll to the immediate next card and then scroll back, it still works.
My listener inside of my outer fragment
final ViewAnimator viewAnimator1 = (ViewAnimator) viewFlipper;
viewAnimator1.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View v){
((definitionFragment) definitionFragment1).update();
((wordFragment) wordFragment1).update();
AnimationFactory.flipTransition(viewAnimator1, FlipDirection.RIGHT_LEFT);
final FragmentTransaction transaction3 = getChildFragmentManager().beginTransaction();
transaction3.detach(definitionFragment1);
transaction3.add(R.id.fragment_definition, definitionFragment1);
final FragmentTransaction transaction4 = getChildFragmentManager().beginTransaction();
transaction4.detach(wordFragment1);
transaction4.add(R.id.fragment_word, wordFragment1);
}
update metod:
public void update(){
DatabaseHandler db1 = new DatabaseHandler(getActivity());
List<VocabWord>words1 = db1.getAllVocabWords();
switch(words1.get(pagenumber).getCategory())
{
case 0:
mDefaultButton.setChecked(true);
break;
case 1:
mRedButton.setChecked(true);
break;
case 2:
mYellowButton.setChecked(true);
break;
case 3:
mGreenButton.setChecked(true);
break;
}
}
Anyone have any idea how to approach this? Or does anyone know how to set a nonexistent offscreenpagelimit and make sure it never deletes any of the pages?

This answer took me exactly 3 weeks to solve! What I did wrong is instead of detaching and adding the fragments you just simply use "replace."

Related

How to get the views which are not visible currently in the linear layout of the recycler view

I was designing an Instagram story type template. I am stuck at a very weird problem. I have used recycler view in the main activity.
MainActivity: (This is just the layout shown. I have change the orientation to Horizontal).
My layout:
Then I have designed a custom adapter and in the layout I have used a linearLayout. When clicked on each view It opens a new Activity which shows the whole story content.
Just like in Instagram when a user opens any story, the user can click on the right side of the screen to get to the next story, or left of the screen to get to the previous one. I tried to implement this same functionality. Opening the story was implemented successfully. The problem comes when I added the functionality of right and left click on the screen. I added two button; one to the right and one to the left. The problem is like, if there are currently 3 views visible, then I can navigate in between these stories only and not to the stories which are not visible in the screen because of the recycler view.
The below code is for right and left clicks
leftArrow = findViewById(R.id.leftArrow);
leftArrow.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(myAdapter.currentPosition - 1 >= 0) {
int firstVis = MainActivity.linearLayoutManager.findFirstVisibleItemPosition();
MainActivity.linearLayoutManager.scrollToPosition(firstVis - 1);
rightOrLeftClicks(myAdapter.currentPosition - 1);
}
}
});
rightArrow = findViewById(R.id.rightArrow);
rightArrow.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(myAdapter.currentPosition + 1 < myAdapter.localDataSet.length) {
int lastVis = MainActivity.linearLayoutManager.findLastVisibleItemPosition();
MainActivity.linearLayoutManager.scrollToPosition(lastVis + 1);
rightOrLeftClicks(myAdapter.currentPosition + 1);
}
}
});
}
Below code is of the function rightOrLeftClicks
public void rightOrLeftClicks(int position) {
finish();
Log.d("rl", "working");
nextView = MainActivity.linearLayoutManager.getChildAt(position);
Log.d("ll", "The last element is " + MainActivity.linearLayoutManager.findLastVisibleItemPosition());
if(nextView != null)myAdapter.onClickView(position, myAdapter.localDataSet[position].symptom, nextView);
}
Below code is for onClickView, It is same code for clicking any view (Story) or clicking the right or left buttons. Basically I just opened the another activity by passing an intent with the next or previous view I obtained when clicked on right or left respectively.
public static void onClickView(int position, String element, View v) {
Intent intent = new Intent(v.getContext(), MainActivity2.class);
idPosition = "";
idPosition = element;
ArrayList<String> passingContent = new ArrayList<>();
currentPosition = position;
passingContent.add(localDataSet[position].description);
passingContent.add(localDataSet[position].imageUrl);
intent.putExtra(element + "", passingContent);
v.getContext().startActivity(intent);
}
The problem is it only gives the visible views to me. Not the rest of the views. I tried auto scrolling so that the next or the previous view become visible but it doesn't seems to work. The last visible position of the child remains the same and it return a null view to me when I try to open the view just after the last visible view.
Assume there are 5 stories. Then I will see only 3 stories in the screen the rest can be seen by scrolling. When I click any of the stories. I can only navigate between 1,2 and 3. When I try to click right from story 3 to see the story 4. The current story is killed by finish() function and null is returned in the nextView variable because of which the story 4 is not loaded and I am returned to the MainActivity.
I have to navigate to all stories present in my recycler view.
Do these changes may help:
1/
I think you should use ViewPager. It automatically snaps to the item without scrollTo to index. Or keep using RecyclerView with the help of SnapHelper
2/
Modify onClickView method not to be static, and don't need View v to work. I see you just need View v just for the context. Why not just pass the context to that method. It's not proper to use a parameter like that, and that approach traps you into 3/ problem.
3/
nextView = MainActivity.linearLayoutManager.getChildAt(position);
You already know how RecyclerView works, just avoid using getChildAt because in some cases, the child you want hasn't been created yet. Base on your code, I think you don't even need to get the nextView
As told by Tam Huynh. The 1st point helped me in getting the new views in the linear layout. The views were working the fine.
There was a problem in the parameter of the function getChildAt. I have to pass the same position I was in previously. Because relatively the position(index) will not change for the child views.
index 0 -> story number 1
index 1 -> story number 2
index 2 -> story number 3
Like if there were story number 1,2 and 3 visible, the index 0 will contain 1st story, index 1 will contain 2nd and index 2 will contain 3rd story. when user clicked the right button on the 3rd story. The 4th story is first visible and now the screen have 2,3 and 4 visible. but the index of the 4th story will remain 3rd only. As now indexing will be like
index 0 -> story number 2
index 1 -> story number 3
index 2 -> story number 4
So, instead of passing position as parameter, currentPosition should be passed in getChildAt

Java if two buttons have the same icons increase score and if not display "wrong match"

Creating a really basic Memory game using Java Swing. I created my GUI with a list of blank buttons where I set the icon property to none.
My code for some of the buttons is:
private void tbtnCard3ActionPerformed(java.awt.event.ActionEvent evt) {
tbtnCard3.setIcon(new javax.swing.ImageIcon(getClass().getResource("/Card3Logo.png")));
if(tbtnCard5.isSelected()){
score++;
lblScore.setText(""+score);
}
}
private void tbtnCard4ActionPerformed(java.awt.event.ActionEvent evt) {
tbtnCard4.setIcon(new javax.swing.ImageIcon(getClass().getResource("/Card7EWaste.png")));
if(tbtnCard7.isSelected()){
score++;
lblScore.setText(""+score);
}
}
private void tbtnCard5ActionPerformed(java.awt.event.ActionEvent evt) {
tbtnCard5.setIcon(new javax.swing.ImageIcon(getClass().getResource("/Card3Logo.png")));
if(tbtnCard3.isSelected()){
score++;
lblScore.setText(""+score);
}
}
I have about 20 toggle buttons and for example the code above works and the scores go up by 1 when a match is found. So for tbtnCard3, if tbtnCard5 is selected the score goes up by 1. Now my question is how would I make it so that if tbtnCard3 is selected but tbtnCard 5 is not selected, display "Wrong Match". Since im using if Selected I'm not too sure how to display "wrong match" when the case is false. It doesn't make sense to say else ifSelected as no parameters can be put either....
In my opinion, the OPs suggestion is not a good approach. You do not want the listener of one button to be "aware" of some other component unnecessarily. Suppose you have an 8-by-8 grid with toggle buttons. You don't want each toggle button listener to be aware of the other 63 toggle buttons.
I believe there is a much simpler (and cleaner) approach. What you want is for the toggle button listener to register and deregister the toggle when the state of the button changes. Let say, you add the toggle button to or remove from a list (most likely a custom class) where you can trigger some logic when the list size reaches two. Then, depending on the outcome of the comparison, it will count a match (and disable these two toggle buttons in the current state), or will display some message like "Try again" and then toggle the buttons to hide the image.
In pseudocode, this will look something like this:
public class ToggleListener implements ItemListener {
public void actionPerformed (ItemEvent event) {
JToggleButton button = (JToggleButton) event.getSource();
if (event.getStateChange()==ItemEvent.SELECTED) {
// TODO Add the button to your list..
} else {
// remove button
}
}
}
In your Swing application, you can create a single instance of the above listener and add it to every single toggle button. And, as you can see, this listener is only responsible to register and unregister the component associated with the triggered event.
The "List Listener" on the other hand, is responsible to trigger the comparison logic when the size of the list reaches two. So, if you click on the same toggle button over and over again, the only thing the button listener will do is add or remove the button from the list depending on the button's current state. However, once a second button is toggled to reveal its image, the list listener will trigger the comparison logic. I am not 100% sure, but I think you could use JavaFX ObservableList interface or one of its implementing classes to do this. If the ListChangeListener.Change class is not suitable to figure out the size of the list to trigger the logic, you will have to implement this on your own. Regardless, in pseudocode, you need to do something like this:
public void onListChange(Event event) {
if (list.size() == 2 && btn1.getIconName().equals(btn2.getIconName())) {
displayMatchMessage();
btn1.setEnabled(false);
btn2.setEnabled(false);
list.clear(); // you should remove matched items from list manually
} else {
displayMismatchMessage();
btn1.setSelected(false); // flip the card
btn2.setSelected(false); // flip the card
// list.clear(); // you should not need this because the setSelected should trigger the Item Listener which should remove item from list.
}
}
Doing something like this is a much cleaner implementation where the button listener have a single job to do and the "list listener" has another job to do. Neither one encroaches on the other's job.

How to display a text in textbox by tapping/clicking the two buttons (combined)

So I've done layouting my android application, the problem now is that, how could I combine the two buttons, like when I click the first block and the 3rd block that will generate a associate "letter" So basically in every combination of buttons there is a corresponding "letter"
Or please do correct me if I'm wrong if using a "button" to implement what I wanted is the right thing to use? If not, please state what's the right way to do to implement what I wanted.
If I haven't explain well, I would state some examples: For e.g clicking the 1st block, 3rd block and the 5th block that generates a letter "z".
Please pardon me if my explanation is confusing. Sorry I am still learning java.
What you can do is create your layout with all the buttons and respective ids and values for example I am giving you one button
<Button
android:id="#+id/btnA"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="A"
android:textSize="16sp" />
just like this create buttons with respective ids and text values...
Now inside your activity setOnClickListener for all buttons.
inside your onCreate()
like this
Button A = (Button)findViewById(R.id.btnA);
Button B = (Button)findViewById(R.id.btnB);
.
.
.
. just like this
then setOnClickListener
A.setOnClickListener(this);
B.setOnClickListener(this);
After this inside your onClick() method just based on the which button clicked append their value to a string. and first declare one global string variable for example String letter;
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btnA:
letter += "A";
break;
case R.id.btnB:
letter += "B";
break;
.
.
Hope this will help
Ok so now I am editing my answer...
m just gonna give you small idea depending on that you have to decide
so as per your question what you want is suppose user press btnA and btnB you want to write z on the screen. This is not a simple job you its actually lengthy. First of all you have to decide on what combination you want to generate what just like btnA and btnB you need to generate z
so keep your clicks same as i have given above just inside your onClick function change the code that I am giving you.
so first
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btnA:
letter += "A";
checkCombo(letter);
break;
case R.id.btnB:
letter += "B";
checkCombo(letter);
break;
.
.
So now create one function named as checkCombo(String letter) with one string parameter
Now the actual part comes where you have to decide what combinations you want so if you want on A and B clicks to generate Z then create a switch case like below
function checkCombo(String mletter) {
String generatedLetter;
switch(letter) {
case "AB":
generatedLetter = 'Z';// or you can set it to your textview here
letter = ""; // if it goes inside any of your switch case clear your
global variable
break;
case "DEF":
generatedLetter = 'P'
letter = "";
break;
}
}
This is just a lengthy solution but will work
Get the button id on click and do your logic like below
First set onClickListener for all buttons then onClick method do like this
#Override
Public void onClick(View v){
switch(v.getId()) {
case R.id.first_button_id:
case R.id.second_button_id:
case R.id.third_button_id:
String value = "your character";
break;
}

Multiple buttons. Passing actions to the next button in Java

Java Android question
I have x, say 5, buttons in a row.
Each button has a different number value displayed on the button.
Button one is active, the rest are not- not clickable. They are greyed out.
To show Button 1 is active it fades up and down.
Once clicked the button pops up a message. The user Ok's that, this activates Button 2, and deactivates Button 1.
Then it happens through all buttons, one by one. The final button doesn't produce the pop up message.
My question...
I want to create a method that sets the first button as current and then once clicked sets the next as current, and so on.
Can anyone tell me how to do this? I don't need to know how to fade buttons etc, its literally how to set button as current, and within that method the user click sets the next button as current.
Many thanks in advance.
EDIT
OK, I've had a go...its not working, but it seems so close...
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_workout_one);
int[] buttonIds = new int[] {R.id.button_1,R.id.button_2,R.id.button_3,R.id.button_4,R.id.button_5};
setButton(buttonIds);
}
private void setButton(int[] buttId){
int isCurrent = 0;
while(isCurrent < 5) {
Button currentButton = (Button) findViewById(buttId[isCurrent]);
//TODO Make current button pulse
currentButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
v.clearAnimation();
v.setBackgroundColor(0xFF00FF00);
v.setFocusable(false);
v.setFocusableInTouchMode(false);
v.setClickable(false);
setTimer();
isCurrent++;
}
});
I know that the problem is the isCurrent++ is not accessible outside the onClick method. How do I right this? Am I close or is this a major funk up and do I have to rethink?
Just use a global variable which track the current button, and check this variable to identify the current active button for determining the action in onClickListener. To fade out a button try this code snippet
button.setClickable(false);
button.setBackgroundColor(Color.parseColor("#808080"));
You need something like this:
private int activeButton = 1;
private void buttonClickHandler(){
switch(activeButton++){
case : 1
button1.setEnabled(true):
// show popup, hide/animate for button 1
break;
case : 2
button2.setEnabled(true);
// same for button 2
case : 3
// same for button 3
case : 4
// same for button 4
}

Android, strange behavior of fragment transaction replace()

I want to use a multipane layout for wider screens. The data is persisted with SQL and each fragment fetches the right data. The extra layout xml files are in resource directory folders.(i.e. layout-w500dp) But i have some strange behavior.
It only seems to work after I select something and then press the back button.
Atm I am using max two FrameLayouts but later I want to do it with four.
I check the level of the deepest selection and assign the fragments accordingly. (Here its only down to lvl 1, but later I need selections up to lvl3).
Here is what I want to achieve.
This gets called in onCreate and when a selection has been made.
private void setScreens(){
int i = getLowestSelection();//returns 0 when nothing is selected.
//And 1 if selection is made in lvl1 ...
int p = 1;
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
if (findViewById(R.id.fragtwo) != null) {
p = 2;
if (i == 1){
SectionsScreen secondFragment = new SectionsScreen();
transaction.replace(R.id.fragtwo,secondFragment);
}
}
if (findViewById(R.id.fragone) != null) {
if(p == 2){
if (i == 0 ){
StatuteScreen statuteScreenFragment = new StatuteScreen();
transaction.replace(R.id.fragone,statuteScreenFragment);
}
}
if (p == 1){
if (i == 0){
StatuteScreen statuteScreenFragment = new StatuteScreen();
transaction.replace(R.id.fragone,statuteScreenFragment);
}
else if (i == 1){
SectionsScreen sectionsScreenFragment = new SectionsScreen();
transaction.replace(R.id.fragone,sectionsScreenFragment);
}
}
}
transaction.addToBackStack(null);
transaction.commit();
}
It only works at the moment if I do the following.
Start application = 1 fragment in portrait and landscape (this is the desired behavior)
Make selection in Portrait = nothing happens !!!! (Here is the problem)
Switch to Landscape = 2 Fragments with the right selection (right behavior) (if I make the initial selection in landscape I need to rotate to Portrait and back again)
Switch to Portrait = LvL 2 Fragment with right Data ( right behavior)
Press Back Button = LvL 1 Fragment (right behavior)
From now on I can switch between portrait to landscape orientation and i get the right behavior for selecting items in all orientations. Even on backpress in landscape showing only one fragment with lvl 1 when selection is taken away.
Why am i getting this behavior?
And is this the right approach in the firstplace?
Considering I want to extend this for further levels and screenWidths!
i.e.:
will backstack function properly here? If anyone needs additional info, just say and i'll be happy to add it!
Silly mistake. I save the selections in an Application Class and i instatiate that in onCreate but i need to reinstantiate before i get the current selection in the getLowestSelection() method

Categories

Resources