First of all english is not my first language but i will try my best.
Also... i am pretty sure my title choice was not the best so sorry for that.
Basically what i wanted to do is a menu with three ImageButtons but there is a tricky part (tricky for me at least) since every time i press one button that same button changes image (to a colored version instead of a grayed out image) and the other two change as well from colored version of their respective images to grayed out ones, actually only one of the other two will change since the purpose of this is to be able to activate only one at a time so it would not be possible to have the other two active at the same time.
Notice that this is not a menu on the top right corner but just a set of three ImageButtons on a activity or Fragment.
I already tried a lot of stuff to make that happen but so far no luck but i think i know why though i can't find a workaround for this since i am actually new in android dev.
what i tried was inside the setOnClickListener of any of those buttons such as:
eventsButton.setOnClickListener(
new View.OnClickListener() {
public void onClick(View view) {
ImageButton eventsButton = (ImageButton) view.findViewById(R.id.eventsButton);
eventsButton.setBackgroundResource(R.drawable.events_icon_active);
eventsButton.setClickable(false);
}
}
);
i tried to add the functions to change the other imageButtons as well like:
eventsButton.setOnClickListener(
new View.OnClickListener() {
public void onClick(View view) {
ImageButton eventsButton = (ImageButton) view.findViewById(R.id.eventsButton);
eventsButton.setBackgroundResource(R.drawable.events_icon_inactive);
eventsButton.setClickable(false);
ImageButton contactsButton = (ImageButton) view.findViewById(R.id.contactsButton);
contactsButton.setBackgroundResource(R.drawable.contacts_icon_inactive);
contactsButton.setClickable(true);
ImageButton interestsButton = (ImageButton) view.findViewById(R.id.interestsButton);
interestsButton.setBackgroundResource(R.drawable.interests_icon_inactive);
interestsButton.setClickable(true);
}
}
);
and i repeated that three time, always setting the other buttons clickable and setting their images to the inactive one (the grayed out one), also setting the button i click as no longer clickable.
But from what i gather i cant do any references to any other buttons inside the eventsButton.setOnClickListener like the buttons interestsButton or contactsButton, it will crash the app as soon as i touch any of those three buttons with the following error message:
Attempt to invoke virtual method 'void android.widget.ImageButton.setBackgroundResource(int)' on a null object reference
And it always point to the first line where i make a reference to another button other then the one used to start the setOnClickListener.
If you can just point me in the right direction i would be tremendously grateful.
All the best
You can declare your ImageViews as final outside the scope of the listener and when the onClickListener(View v) is called you can then just call setBackground because they are final and you can reference them from inside the listener.
Something like this:
final ImageView view1 = (ImageView) findViewById(R.id.view1id);
final ImageView view2 = (ImageView) findViewById(R.id.view2id);
view1.setOnClickListener(
new View.OnClickListener() {
public void onClick(View view) {
// do whatever you want to the ImageViews
// view1.setBackground...
}
}
);
eventsButton.setOnClickListener(
new View.OnClickListener() {
public void onClick(View view) {
ImageButton contactsButton = (ImageButton) view.findViewById(R.id.contactsButton);
contactsButton.setBackgroundResource(R.drawable.contacts_icon_inactive);
contactsButton.setClickable(true);
}
}
);
Your problem is in view.findViewById(R.id.contactsButton): view here is the button being clicked (the events one), and by calling view.findViewById(contactsButton) you are implicitly saying that the contact button is a child of view, which is not.
Just use findViewById() (from Activity), getActivity().findViewById() (from Fragments), or better container.findViewById() (if you have a reference to the layout containing the three buttons).
I'm not saying that yours is the most efficient way to deal with a menu, just pointing out your error.
You can first make things simple; I suggest:
you add 3 array (Arraylist might be better) fields in your activity class, one for the buttons, one for the active resources and one for the inactive resources
initialize those arrays in the onCreate method;
define a single onClickListener object and use it for all the buttons; Use a loop in the onClick method, see bellow.
In terms of code, it looks like this:
ImageButton[] buttons;
int[] activeResources;
int[] inactiveResources;
protected void onCreate2(Bundle savedInstanceState) {
View.OnClickListener onClickListener = new View.OnClickListener(){
public void onClick(View view) {
ImageButton clickedButton = (ImageButton) view;
for(int i = 0; i<buttons.length; i++){
ImageButton bt = buttons[i];
if(clickedButton==bt){
bt.setBackgroundResource(inactiveResources[i]);
bt.setClickable(false);
}else{
bt.setBackgroundResource(activeResources[i]);
bt.setClickable(true);
}
}
}
};
buttons = new ImageButton[3];
activeResources = new int[3];
inactiveResources = new int[3];
int idx = 0;
buttons[idx] = (ImageButton) findViewById(R.id.eventsButton);
inactiveResources[idx] = R.drawable.events_icon_inactive;
activeResources[idx] = R.drawable.events_icon_active;
idx = 1;
buttons[idx] = (ImageButton) findViewById(R.id.contactsButton);
inactiveResources[idx] = R.drawable.contacts_icon_inactive;
activeResources[idx] = R.drawable.contacts_icon_active;
idx = 3;
buttons[idx] = (ImageButton) findViewById(R.id.interestsButton);
inactiveResources[idx] = R.drawable.interests_icon_inactive;
activeResources[idx] = R.drawable.interests_icon_active;
for(int i =0; i<buttons.length; i++){
buttons[i].setBackgroundResource(activeResources[i]);
buttons[i].setOnClickListener(onClickListener);
}
}
Do not expect it to run right the way, I am giving only ideas, you have to look and see if it fit for you are looking for.
Related
I dynamically create Buttons by entering a word. If I write "met", it appears on the screen - one Button per letter. The same thing happens for the next word I enter, and it appears below the previous word --- as shown in the image above.
When I click on a Button it turns green. My question is, what is the best way to disable the clicking of a row of Buttons. Meaning, if the user clicks on the 'm' in "met" I want the user to only be able to click on the Buttons in "met" and to not be able to click on any of the Buttons in "had", "goes", or "ran"
Here is my code:
EDIT
int size = enter_txt.getText().toString().length();
for (int i=0; i<size; i++){
final Button dynamicButtons = new Button(view.getContext());
dynamicButtons.setLayoutParams(rlp);
dynamicButtons.getLayoutParams().width = 130;
dynamicButtons.getLayoutParams().height = 130;
dynamicButtons.setTag("0");
dynamicButtons.setId(1);
dynamicButtons.setText(edit_text_array[i]);
dynamicButtons.setBackgroundResource(R.drawable.button);
button_list.add(dynamicButtons);
linearLayout2.addView(dynamicButtons, rlp);
dynamicButtons.setOnClickListener(
new View.OnClickListener()
{
public void onClick(View view)
{
int i=0;
LinearLayout ll = (LinearLayout) dynamicButtons.getParent();
for(i=0; i<list_of_ll.size();i++){
if (ll == list_of_ll.get(i)){
list_of_ll.get(i).setId(i);
break;
}
}
if(list_of_ll.get(i).getId()==i)
ButtonOnClick(view);
}
});
}
linearLayout2.setId(0);
linearLayout2.setTag("0");
list_of_ll.add(linearLayout2);
EDIT
I created a List of the LinearLayouts for each row of Buttons. The Buttons turn green if the id of the LinearLayout is set to 1. When I click on a Button I want that LinearLayout to stay at 1 and have all other rows/LinearLayouts set to 0 so they become unclickable.
Currently, every Button I click turns green even if it's in a different row. Can someone please help me solve this issue?
Why you don't set Id in the for loop so that you are able to refer and set the onlicklistener to null like jpcrow already mentioned.
Set Id like:
YourCreatedBtn.setId(i+1);
//Id's setted programmatically don't.
have to be unique... But they should be
a positive number (referring to the
android documentation)
And in your on click method simply set onclicklistener for specified Id's to null. Just a hint, hope it helps
Update regarding Thread-openers Comment
I found two simple ways but i would prefer the one which is not commented out in the buttonIsClicked:
LinearLayout llrow;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
llrow = (LinearLayout) findViewById(R.id.test_layout);
//Adding 5 Buttons
for(int i = 0; i<5; i++) {
Button mybtn = new Button(this);
//set LayoutParams here
mybtn.setId(5);
mybtn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
buttonIsClicked(v);
}
});
llrow.addView(mybtn);
}
}
private void buttonIsClicked(View v) {
/*ArrayList<View> myButtons = llrow.getTouchables();
for(int i = 0; i < llrow.getChildCount(); i++){
myButtons.get(i).setOnClickListener(null);
}*/
for(int i = 0; i<llrow.getChildCount(); i++){
llrow.getChildAt(i).setOnClickListener(null);
}
}
It's just a simplified Version of your code, but i'm sure you will get the Content..
What if found out is, that you don't have to set the ID in both cases.. You can easily get all the child over
YourRowLinearLayout.getChildAt(starting from 0 to n-1-Views you added)...
I didn't found a way around the for-loop... But this small-little loop will not break your neck regarding to Performance..
The outcommented-code is the second Approach, finding all the Child over getTouchables which logically leads to an ArrayList and that's exactly the reason why i don't like it. You have to initialize an arraylist...... However, this also won't break your neck regarding to Performance but a penny saved is a penny got! ;) Hope it helps and everything is clear. Both of them work! Please mark as accepted answere if it fits your Needs...
You have to distinguish between the two rows, either add them to different ViewGroups or you can use View.setTag(int key, Object tag)
I am trying to make a calculator for Android. Here is the code for my buttons:
int[] button_ids = {
R.id.BtnNum0, R.id.BtnNum1, R.id.BtnNum2, R.id.BtnNum3, R.id.BtnNum4, R.id.BtnNum5, R.id.BtnNum6,
R.id.BtnNum7, R.id.BtnNum8, R.id.BtnNum9, R.id.BtnAdd, R.id.BtnSub, R.id.BtnDiv, R.id.BtnMult,
R.id.BtnClear, R.id.equals
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
EditTextValue = (EditText) findViewById(R.id.editText1);
TVValue = (TextView) findViewById(R.id.textView1);
buttons = new ArrayList<Button>();
for(int id : button_ids) {
Button button = (Button)findViewById(id);
button.setOnClickListener(this);
buttons.add(button);
}
}
How I can change this part to a block of code where I won't have to declare the IDs of the buttons? (e.g. R.id.BtnNum0)
int[] button_ids = {
R.id.BtnNum0, R.id.BtnNum1, R.id.BtnNum2, R.id.BtnNum3, R.id.BtnNum4, R.id.BtnNum5, R.id.BtnNum6,
R.id.BtnNum7, R.id.BtnNum8, R.id.BtnNum9, R.id.BtnAdd, R.id.BtnSub, R.id.BtnDiv, R.id.BtnMult,
R.id.BtnClear, R.id.equals
};
I have been searching for an answer, but I still can't find a solution.
What you can do, since this code seems to only set a single OnClickListener for all Buttons, is to do it in xml
For each Button set
android:onClick="functionName"
then in your code you can do away with all of the id's and your for loop. In Java just create a function like
public void functionName(View v)
{
switch (v.getId())
{
case R.id.buttonId:
// do work for this Button
break;
...
}
The way you are doing it is fine but this is how I prefer to handle this situation. You just have to give all of the Buttons the same function name in xml then use that name as your function name in Java. You also just have to be sure to declare the function with a void return type and make sure it takes a View as its one and only parameter as in my example.
The Button Docs also have an example of this
in your layout file add this to every button
<Button
...
android:onClick="btnClicked"
.../>
then in your code add this method and check for each button in this method
public void btnClicked(View v)
{
switch(v.getId())
{
case R.id.BtnNum0:
// your code
break;
....
}
}
That is likely the best solution unfortunately, unless you use some sort of annotation framework which still doesn't cut down much on the boilerplate.
edit:
You could try to get a pointer to whatever ViewGroup is holding the Button views and then getting all of its children, and then looping through them while casting them to Buttons as you go.
For example: If your Button objects in XML are housed in a LinearLayout, you could get the pointer to that and do something like this:
for(int i=0; i < ((ViewGroup)v).getChildCount(); ++i) {
Button nextChild = (Button) ((ViewGroup)v).getChildAt(i);
}
Of course, I recommend against this, but it is still a possibility.
As trevor-e suggested, you can give an annotation processor a try. Android Annotations can simplify your code to:
#Click
public void BtnNum0() {
// Button 0 clicked
}
#Click
public void BtnNum1() {
// Button 1 clicked
}
// etc.
If you go this route, please do try to use names following the Java convention as the button names correspond with function names.
Im going to write some android app, which will basically consists of two activities. So first should have a lot of buttons (100+) and on click on any of them I will just get some special id and move to second activity. But is there any alternative to declare that hundreds of buttons and copy/paste one piece of code to every of them setting almost same onClickLister? Is there any special construction? Thanks
Edit: every of buttons are actually indexed from 1 to n. And on the click second activity will be launched and get that index to show it. I cant basically use any spinner or smth else, because there will be 3 rows of clickable things and each of them carring different images
Edit 2: so, to give you an idea, im going to do some table of buttons like in Angry Birds menu when you actually choosing the level you want to play. So, on click you will get id of button and start second activity
Call the method to add buttons
private void addButton(){
LinearLayout view = (LinearLayout) findViewById(R.id.linear_layout_id_here);
Button btn = null;
int w = 50;
int h = 25;
for(int i=1; i<100; i++) {
btn = new Button(this);
btn.setLayoutParams(new LayoutParams(w,h));
btn.setText("button " +i);
btn.setTag(""+i);
btn.setOnClickListener(onClickBtn);
view.addView(btn);
btn = null;
}
}
Call this method for handling onclick on button
private View.OnClickListener onClickBtn = new View.OnClickListener() {
public void onClick(View view) {
final int tag = Integer.parseInt(view.getTag().toString());
switch (tag) {
case 1:
// Do stuff
break;
case 2:
// Do stuff
break;
default:
break;
}
}
};
You should use a ListView.
ListViews are great for handling a lot of items at the same time. They are also natural for the user. Additionally, you use only one click listener - OnItemClickListener.
There's a useful example on how to work with ListViews in the Android Referenence.
You may add buttons in code, something like this:
#Override
public void onCreate(Bundle savedInstanceState) {
/*your code here*/
GroupView gw =findViewById(R.id.pnlButtonscontainer); //find the panel to add the buttons
for(int i=0; i<100; i++) {
Button b = new Button(this);
b.setLayoutParameters(new LayoutParameters(w,h));
b.settext = i+"";
b.setOnClickListener(new OnClickListener(){
});
}
}
I coded directly into browser, so some syntax error may appear in my code, but this is the point, a way, not the only one, to add 100 buttons.
I have created a bunch of ImageButtons programmatically while in a for loop. They have worked fine as the data displayed in a HorizontalScrollView. Now I need each one to go dim or bright when clicked. First click will setAlpha(45); second click will setAlpha(255);.
I don't think I fully understand how the Views and onClickListener works yet. It seems the onClick function examples I find take a View. How would that function know which button is clicked? Perhaps there is an easier way to do what I want?
Here are the ImageButtons.
TableRow tr0 = new TableRow(this);
tr0.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
for(int but=0; but<ClueList.size(); but++){
ImageButton clueBut = new ImageButton(this);
clueBut.setBackgroundResource(0);
clueBut.setImageBitmap(ClueList.get(but).btmp);
//clueBut.setOnClickListener(this);
tr0.addView(clueBut);
}
Is there something I need to do to make the buttons identifiable? And how would that pass in through into the onClick function to be used?
-: Added Information :-
I am starting to wonder if the problem isn't with the buttons, but with the way I built the screen. More information added.
The Game activity is the main game, which uses the PuzzleView for the upper part of the screen holding the game grid. The lower part is where the ImageButtons are and I built them in place in the Game class.
public class Game extends Activity{
//various variables and stuff
private PuzzleView puzzleView; // The PuzzleView is from another .java file
// public class PuzzleView extends View
#Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
LinearLayout mainPanel = new LinearLayout(this);
mainPanel.setOrientation(LinearLayout.VERTICLE);
puzzleView = new PuzzleView(this);
mainPanel.addView(puzzleView);
HorizontalScrollView bottom = new HorizontalScrollView(this);
mainPanel.addView(bottom);
TableLayout clues = new TableLayout(this);
bottom.addView(clues);
TableRow tr0 = new TableRow(this);
for(int but=0; but<ClueList.size(); but++){
ImageButton clueBut = new ImageButton(this);
clueBut.setImageBitmap(ClueList.get(but).btmp);
tr0.addView(clueBut);
}
When I try to add the ClickListener(this) I get errors about this not being able to be a Game. I have similar problems in the onClick(View v) function referencing the View. Are these problems because I am building the buttons in the Game Activity instead of a View class?
Thanks
When you set up an OnClickListener and implement the onClick(View v) callback, it's the Dalvik VM the one that will call that method each time the View is clicked, and it will pass the View instance as a parameter. Thus, the code you write inside that method will be applied only to the View that received the click and not to any other View. Add something like this to your loop:
clueBut.setOnClickListener(new OnClickListener() {
public void onClick (View v) {
if (v.getAlpha() == 1f)
v.setAlpha(0.2f);
else
v.setAlpha(1f);
}
});
In the onClick event:
public void onClick(View currentView)
{
Button currentButton = (Button)CurrentView;
//Do whatever you need with that button here.
}
To identify each view uniquely use the property
View. setId(int)
In your case the code would look something like this
for(int but=0; but<ClueList.size(); but++){
ImageButton clueBut = new ImageButton(this);
clueBut.setBackgroundResource(0);
clueBut.setImageBitmap(ClueList.get(but).btmp);
clueBut.setId(but);
//clueBut.setOnClickListener(this);
tr0.addView(clueBut);
}
Inside the onclick listener match the id of the view using findViewByID()
I have a LinearLayout comprising of a few Buttons and I add this to my activity in the onCreate(..) method with setContentView(R.layout.myscreen). No surprises so far.
How do I get a reference to an iterator to these buttons? I'd like to add listeners to them but I'd rather not directly reference the Button's using their android:id.
Similar questions have been asked here and here but they don't quite answer my question.
Try something like this provide an id root_layout in xml to LinearLayout
LinearLayout mLayout = (LinearLayout) findViewById(R.id.root_layout);
for(int i = 0; i < mLayout.getChildCount(); i++)
{
Button mButton = (Button) mLayout.getChildAt(i);
mButton.setOnClickListener(this);
}
Where mLayout is object of you Linear Layout and Your activity must implements OnClickListener and here goes general listener
#Override
public void onClick(View v)
{
Button mButton = (Button)v;
String buttonText = mButton.getText().toString();
}
NOTE: For this to work properly you Linear Layout must only contains button no other views
You should take a look at my answer here.
In short. I'd assign the buttons a listener by setting the onClick attribute in the XML layout on each Button.
Inside of your Activity you'll need a public method like the one below which basically is what you want to do in your listener.
public void myFancyMethod(View v) {
// do something interesting here
}
If you want to go for accessing other elements you may try following syntax:
<ElementClass> <referencevariable> = (<ElementClass>) findViewById(R.id.<id_of_the_element>);
For Example:
TextView textView= (TextView) findViewById(R.id.t1); //I used t1 to refer my textview in the Layout.
This might work.
Then you can use these views with their inbuilt methods to perform as many as work you want.