I am trying to create an adapter for a RecyclerView, where each view contains some information and two buttons, one for removing the view and one for updating the information. I set the listener as follows, and I get the actions to work as I want to (i.e. the removeRecepie and chooseNewRandomRecepie does what I want them to do).
However, sometimes, seemingly randomly, the getAdapterPosition sends the incorrect position. Thus the removal or updating happens to the incorrect view (I have tested the output of getAdapterPosition, and the output is consistent with the view that changes, i.e. the wrong one). I have written the setListener as follows:
void setListener(View view){
Button removeButton = view.findViewById(R.id.remove_button);
removeButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
removeRecepie(getAdapterPosition());
}
});
Button newRandomButton = view.findViewById(R.id.new_random);
newRandomButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
chooseNewRandomRecepie(getAdapterPosition());
}
});
}
I would be really grateful for any help, or pointers to help. Please let me know if there is any further information I can include to help you help me :)
You should be use onBindViewHolder.
public void onBindViewHolder(#NonNull MyViewHolder holder, int position) {
holder.removeButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
removeRecepie(position);
}
});
holder.removeButton.SetOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
chooseNewRandomRecepie(position);
}
});
}
public class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
Button removeButton;
Button newRandomButton;
public MyViewHolder(#NonNull View itemView) {
super(itemView);
removeButton = itemView.findViewById(R.id.removebutton);
newRandomButton = itemView.findViewById(R.id.newRandomButton);
}
}
Related
Below code of adapter of RecyclerView
public interface SelectMarket {
void selectMarket(DataMarket dataMarket);
}
public class viewHolder extends RecyclerView.ViewHolder{
TextView marketTitleName;
public viewHolder(#NonNull View itemView) {
super(itemView);
marketTitleName = itemView.findViewById(R.id.market_title_custom);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
selectMarket.selectMarket(marketName.get(getAdapterPosition()));
Toast.makeText(ctx, "id "+getAdapterPosition(), Toast.LENGTH_SHORT).show();
}
});
}
}
In the code I shows you the ViewHolder
where I set onClickListener
I want to click on that and then go to other Fragment called SelectRoomFragment
and in Method of SelectMarket() I wrote inside the codes which will help me to go the the Next Fragment like this :
#Override
public void selectMarket(DataMarket dataMarket) {
SelectRoomFragment selectRoomFragment= new SelectRoomFragment();
Bundle args = new Bundle();
args.putString("market",dataMarket.getTitle());
selectRoomFragment.setArguments(args);
getFragmentManager().beginTransaction().add(R.id.fragment_container,
selectRoomFragment).commit();
}
The Output Is
Which is not looking Good like I want.
move the code below to onBindViewHolder
marketTitleName = itemView.findViewById(R.id.market_title_custom);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
selectMarket.selectMarket(marketName.get(getAdapterPosition()));
Toast.makeText(ctx, "id "+getAdapterPosition(),Toast.LENGTH_SHORT).show();
}
});
I'm super new in Java! Pardon for this question although there are similar ones but I'm completely clueless on fixing my problem.
I'm trying to set an OnClickListener for each ImageButton to open a new activity.
The first ImageButton works but not for the subsequent ones, it is unclickable in AVD.
Would greatly appreciate some help on it!
public class CharacterSelect extends AppCompatActivity {
ImageButton arrowbtnright;
ImageButton contchibtn;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_character_select);
arrowbtnright = (ImageButton) findViewById(R.id.arrowbtnright);
contchibtn = (ImageButton) findViewById(R.id.contchibtn);
arrowbtnright.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startActivity(new Intent(CharacterSelect.this, CharacterSelect2.class));
contchibtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startActivity(new Intent(CharacterSelect.this, MiniChallenge1.class));
}
});
}
});
}
You are currently adding the listener of the second button, from inside the listener of the first button, this is probably not what you want to do .
Try putting both at the same level, i.e :
arrowbtnright.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(final View v) {
startActivity(new Intent(CharacterSelect.this, CharacterSelect2.class));
}
});
contchibtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(final View v) {
startActivity(new Intent(CharacterSelect.this, MiniChallenge1.class));
}
});
I am trying to implement a quiz whereby the user selects one from four buttons. When they click on the button it becomes selected, but then what I want to do is make any other button that was selected before to be reset to normal. This is my class and code, but it doesn't disable the other buttons:
public class QuizOne extends Fragment{
Button one;
Button two;
Button three;
Button four;
boolean selected = false;
public QuizOne(){
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.quiz, container, false);
one = (Button) rootView.findViewById(R.id.ones);
two = (Button) rootView.findViewById(R.id.twos);
three = (Button) rootView.findViewById(R.id.threes);
four = (Button) rootView.findViewById(R.id.fours);
selectedButton();
return rootView;
}
public void selectedButton(){
one.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(selected){
one.setBackgroundColor(Color.YELLOW);
}
else {
one.setBackgroundColor(Color.GRAY);
selected = true;
}
}
});
two.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(selected){
two.setBackgroundColor(Color.YELLOW);
}
else {
two.setBackgroundColor(Color.GRAY);
selected = true;
}
}
});
three.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(selected){
three.setBackgroundColor(Color.YELLOW);
}
else {
three.setBackgroundColor(Color.GRAY);
selected = true;
}
}
});
four.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(selected){
four.setBackgroundColor(Color.YELLOW);
}
else {
four.setBackgroundColor(Color.GRAY);
selected = true;
}
}
});
}
}
So its the selectedButton() method that I am struggling on. Because say if a user clicks on a button and then changes their mind after and selects another button then the previous button should be disabled. Also after clicking the button I want to go to the next tab
You might want to rethink your whole design. There's easier ways with way less code. Try something like this :
public class QuizOne extends Fragment implements View.OnClickListener {
....
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.quiz, container, false);
one = (Button) rootView.findViewById(R.id.ones);
one.setOnClickListener(this);
// and so on ...
#Override
public void onClick(View v) {
setButtonsGray();
v.setBackgroundColor(COLOR.Yellow);
}
private void setButtonsGray(){
one.setBackgroundColor(COLOR.Gray);
two.setBackgroundColor(COLOR.Gray);
// and so on ...
}
If i clearly understand your problem , one way to do this if you want to follow your first write logic is when you click your button to set yellow color to it and gray color to evryone exept clicket button
public void selectedButton() {
one.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
one.setBackgroundColor(Color.YELLOW);
two.setBackgroundColor(Color.GRAY);
three.setBackgroundColor(Color.GRAY);
four.setBackgroundColor(Color.GRAY);
}
});
two.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
two.setBackgroundColor(Color.YELLOW);
one.setBackgroundColor(Color.GRAY);
three.setBackgroundColor(Color.GRAY);
four.setBackgroundColor(Color.GRAY);
}
});
three.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
three.setBackgroundColor(Color.YELLOW);
one.setBackgroundColor(Color.GRAY);
two.setBackgroundColor(Color.GRAY);
four.setBackgroundColor(Color.GRAY);
}
});
four.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
four.setBackgroundColor(Color.YELLOW);
one.setBackgroundColor(Color.GRAY);
two.setBackgroundColor(Color.GRAY);
three.setBackgroundColor(Color.GRAY);
}
});
}
but there are many ways to achive this for sure..
Well, Suppose there is an Activity called MainActivity and there are two layouts called layout1 and layout2 both have few buttons. By default MainActivity layout is layout1 like following:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout1);
Now what I did actually is by clicking a button in layout1 the second layout is set like following:
someBtn1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
setContentView(R.layout.layout2);
}
});
There are another button in layout2 to return back to layout1 like following:
someBtn2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
setContentView(R.layout.layout1);
}
});
Problem is when I returned back to layout1 then OnClickListener of someBtn1 is not working. It seems I need to set OnClickListener again for someBtn1 of layout1.
How I can write code to make them work perfectly with best practices ?
The best practice is to use fragments instead of change the content view.
In your code, setContentView with layouts recreate (inflate) all your views every time, so the call setContentView(R.layout.layout1) in someBtn2 click listener will create a new button without the associated listener.
If you don't want to use fragments you can do this:
private View view1, view2;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
view1 = getLayoutInflater().inflate(R.layout.layout1, null);
view2 = getLayoutInflater().inflate(R.layout.layout2, null);
setContentView(view1);
The listeners will be:
someBtn1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
setContentView(view2);
}
});
someBtn2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
setContentView(view1);
}
});
If you just want to play around with your current code, a solution for your problem is that the listeners must be redeclared when the layout changes, as follows:
someBtn1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
setContentView(R.layout.layout2);
someBtn2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
setContentView(R.layout.layout1);
}
});
}
});
someBtn2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
setContentView(R.layout.layout1);
someBtn1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
setContentView(R.layout.layout2);
}
});
}
});
An alternative to avoid declaring the listeners twice is to declare two methods to handle the layout changes and use the onClick property of the button in each of the layouts, for example:
public void setLayout1(View view) {
setContentView(R.layout.layout1);
}
public void setLayout2(View view) {
setContentView(R.layout.layout2);
}
In layout1.xml:
<Button
android:id="#+id/someBtn1"
android:onClick="setLayout2"/>
In layout2.xml:
<Button
android:id="#+id/someBtn2"
android:onClick="setLayout1"/>
However, if you want to follow best practices, the best practice is not to mix layouts in the same activity, but instead declare two different activities (each one with its own layout) and call one activity or the other depending on the button that was clicked. Suppose that you are in Activity1 and want to call Activity2, then go back to Activity1:
In Activity1.java:
someBtn1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
startActivity(new Intent(this, Activity2.class));
}
});
In Activity2.java:
someBtn2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
finish();
}
});
One way of doing this is loading both views in onCreate(...), and then switching between them by making the one you don't want invisible. Something like the following:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
inflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
LayoutParams default_layout_params = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
View view1 = inflater.inflate(R.layout.layout1, null);
addContentView(view1, default_layout_params);
View view2 = inflater.inflate(R.layout.layout2, null);
addContentView(view2, default_layout_params);
view2.setVisibility(View.INVISIBLE);
view1.setVisibility(View.VISIBLE);
view1.bringToFront();
At the time you callback layout1, data must be set again.
You could merge both layouts in one and then use ViewFlipper to switch between them.
When you are seting layout2, you should also set up OnClickListener to someBtn1 and vice versa, I'd suggest something like this. But as in prevoius answer, in general you should avoid mixing layouts in such manner.
public class MainActivity extends Activity {
private final View.OnClickListener setLayout1Listener = new View.OnClickListener() {
#Override
public void onClick(View view) {
setContentView(R.layout.layout2);
((Button)findViewById(R.id.Btn2Id)).setOnClickListener(setLayout2Listener);
//do other stuff
}
};
private final View.OnClickListener setLayout2Listener = new View.OnClickListener() {
#Override
public void onClick(View view) {
setContentView(R.layout.layout1);
((Button)findViewById(R.id.Btn1Id)).setOnClickListener(setLayout1Listener);
//do other stuff
}
};
#Override
public void onCreate(final Bundle savedInstance) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout1);
((Button)findViewById(R.id.Btn1Id)).setOnClickListener(setLayout1Listener);
//do other stuff
}
}
Please don't answer already answered
I already asked this question, but I think I wasn't clear enough! My onClick methods for buttons that were obtained by inflating a layout are not working how do I fix this have I forgot to do something in my code?
Updated:
Now with the following code I get a nullpointerexception when I set the onClickListener what is wrong
Here is some of my code:
(note it is not complete you won't see onCreate!)
LayoutInflater inflater = LayoutInflater.from(getBaseContext());
View playv = inflater.inflate(R.layout.play, null);
Button updateLevel = (Button) playv.findViewById(R.id.updateLevel);
updateLevel.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
setLevelOnClick(v);
}
});
View levelv = inflater.inflate(R.layout.level, null);
Button gotomenu = (Button) levelv.findViewById(R.id.tomenu);
gotomenu.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
toMenuOnClick(v);
}
});
Andrew,
Try:
LayoutInflater inflater = LayoutInflater.from(context);
View v = inflater.inflate(R.layout.root_view, null);
Button updateLevel = (Button) v.findViewById(R.id.updateLevel);
updateLevel.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
setLevelOnClick(v);
}
});
Button goBackMainMenu = v.inflate(R.layout.play, null).findViewById(R.id.tomenu);
goBackMainMenu.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
toMenuOnClick(v);
}
});
this is assuming root_view is the View containing the Button objects.