Currently I am working on an app that has somewhat of a basic calculator layout and functions. I have 8 edittext and a grid of 9 buttons. With the onClicklistener method is there a better way of handling this instead of nesting a long if or switch statement for each Edittext?
private View.OnClickListener mListener = new View.OnClickListener() {
public void onClick(View v) {
switch (v.getId() /*to get clicked view id**/) {
case R.id.btn_1:
if edt_1.hasFocus() {
edt_1 = btn_1.getText()
}
if edt_2.hasFocus() {
edt_2 = btn_1.getText()
}
break;
case R.id.btn_2:
if edt_1.hasFocus() {
edt_1 = btn_1.getText()
}
if edt_2.hasFocus() {
edt_2 = btn_1.getText()
}
break;
default:
break;
}
}
I was thinking maybe it would be better to use a hasFocus() method and listen for clicks from there or a while loop, then maybe pass a variable?
Thanks in advance..
Hear is a way where you can small your code. just add android:onClick="onClick" in every button of your grid layout and do following in java file,
public void onClick(View v) {
Button b=(Button)v;
String s+=b.getText();
}
This two line get text from your button and set to the String s.
if you want to create calculator that function real-time calculation like this calculator
APK:https://play.google.com/store/apps/details?id=com.androchunk.calculator
then you can find free source code of calculator project as well as tutorial video that help you to create calculator and understand working of calculator.
Tutorial videos:https://www.youtube.com/playlist?list=PLdMmtAIsH0KYiKrdpbzat6t96Nb1_k3_1
Related
So we are working on a quiz game/app and we have a problem with just one thing.
We got 4 buttons for the possible answers and only one of them is the correct one (obviusly). They are regular buttons with text on them, not the radio ones. The thing is that in order to avoid creating an activity for each question we wanna keep the buttons in one activity, and when pressed on the "correct answer" to change the buttons functions to be different. For example buttons 1,2,3 all send the player to gave over screen, while button 4 is the correct one. Then it should change the text that is displayed on the buttons and change all the buttons' functions so that 1,3,4 are now the "game over buttons" and 2 is the correct one. We tried if statements and integers, and booleans, to no avail. Any hints or solutions that could help us?
Thanks
Given your current setup I'd have each button's onClick call a method like validateCorrectAnswer(int buttonNumber) and then from there you'd do your validations. So for button1 you'd call validateCorrectAnswer(1).
From validateCorrectAnswer(...) you'd have an array of correct answers, so it could be something like int[] correctAnswers = {4, 2, 3, 4, 1, 3, 2, 1, ...}; and depending on which question they are on you'd check. So let's say you are on question 3 you'd check correctAnswers[2] == buttonNumber.
So to simplify that further within your activity store what question they are currently on in a global variable, something like private int currentQuestion = 0 and then after each question you increment that number.
So the final method would be something like:
void validateCorrectAnswer(int buttonNumber) {
if (correctAnswer[currentQuestion] == buttonNumber) {
currentQuestion++;
// correct answer, cool move on
} else {
// wrong answer, game over
}
}
In your question class, you can set the answer to a text / button id and check on a button click if the button text / id is the same as your answer.
Also, see this example from butterknife:
//Specify multiple IDs in a single binding for common event handling.
#OnClick({ R.id.door1, R.id.door2, R.id.door3 })
public void pickDoor(DoorView door) {
if (door.hasPrizeBehind()) {
Toast.makeText(this, "You win!", LENGTH_SHORT).show();
} else {
Toast.makeText(this, "Try again", LENGTH_SHORT).show();
}
}
source: Butterknife docs
You could use the setTag(tagValue) and getTag(tagValue) methods for the 4 buttons.
1 - correct
0 - wrong
And then just switch the tagValues according to the answer given.
#Override
public void onClick(View view) {
int answer = 0;
if(view instanceof Button) {
answer = (int) ((Button)view).getTag();
}
if(answer == 1) {
//true answer
refreshButtons();
} else {
//game over
}
Log.d("TAG", "a: "+answer);
}
public void refreshButtons () {
questionNr ++;
Log.d("TAG", "q: "+questionNr);
setAnswers(questionNr);
}
public void setAnswers (int question) {
switch (question){
case 1: // Second question
v1.setTag(0);//wrong
v2.setTag(1);//correct
v3.setTag(0);//wrong
v4.setTag(0);//wrong
break;
case 2:// Third question
v1.setTag(0);//wrong
v2.setTag(0);//wrong
v3.setTag(1);//correct
v4.setTag(0);//wrong
break;
case 3:// Forth question
v1.setTag(0);//wrong
v2.setTag(0);//wrong
v3.setTag(0);//wrong
v4.setTag(1);//correct
break;
}
}
You could also setup the texts for the other views in the same setAnswer() Method
The onCreate() method could be something like this :
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//here you setup the answers for the first question
v1 = (Button) findViewById(R.id.button1);
v1.setOnClickListener(this);
v1.setTag(1);
v2 = (Button) findViewById(R.id.button2);
v2.setOnClickListener(this);
v2.setTag(0);
v3 = (Button) findViewById(R.id.button3);
v3.setOnClickListener(this);
v3.setTag(0);
v4 = (Button) findViewById(R.id.button4);
v4.setOnClickListener(this);
v4.setTag(0);
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.
I create a whole layout setup in XML then attempt to attach listeners to the buttons using findViewById(). The problem I am having now is that the View parameter I receive in the method does not contain the ID of the view I clicked: 830009633920 vs 2131099657.
Button btnNext = (Button)findViewById(R.id.btnNext);
btnNext.setOnClickListener(this);
#Override
public void onClick(View view) {
if (view.getId() == R.id.btnNext) {
...
}
}
How about this:
Button btnNext = (Button)findViewById(R.id.btnNext);
btnNext.setOnClickListener(this);
#Override
public void onClick(View view)
{
switch (view.getId())
{
case R.id.btnNext:
...
break;
case R.id.foo:
...
break;
}
}
That should be working, so my only guess without seeing the rest of the code or layout is that you have set click handlers on two items that overlap.
If you plan on making an Android Library project switch like this will not work due to a recent change in the tool chain.
http://tools.android.com/tips/non-constant-fields
In general I find it is much simpler to use an anonymous class the handle clicks rather than a large single handler.
btnNext.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View view)
{
...
}
});
You might try this approach just to debug that the item you expect to get the click is what you are pressing, to make sure you don't have layout issues.
Try skipping the IDs, and just compare the actually view object. so something like this:
#Override
public void onClick(View view) {
if (view.equals(btnNext)) {
...
}
}
I am creating a small calc app with EditText views and Im running into an runtime exception when the user leaves an EditText view empty causing the ParseInt to try and Parse nothing. Ive read that I need to 'Try' and 'Catch' this error before it occurs, but Im unsure of where and how to do this!
Any advice is much appreciated!
Here is my code:
public class HandlerExamples extends Activity implements OnClickListener {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button button = (Button)findViewById(R.id.testButton);
button.setOnClickListener(this);
public void onClick(View v) {
String a,b,t;
double vis;
EditText txtbox1 = (EditText)findViewById(R.id.A);
EditText txtbox2 = (EditText)findViewById(R.id.B);
EditText txtbox3 = (EditText)findViewById(R.id.t);
TextView tv = (TextView) findViewById(R.id.Answer);
a = txtbox1.getText().toString();
b = txtbox2.getText().toString();
t = txtbox3.getText().toString();
vis = ((Integer.parseInt(a)*1) + (Integer.parseInt(b)*2)) / (Double.parseDouble(t));
tv.setText(double.toString(vis));
}
}
Thanks so much!
public void onClick(View v) {
int id = v.getId();
switch(id){
case R.id.xx:
//do things xx click
break;
case R.id.yy:
//do things yy click
break;
}
}
you can get the view id to know whick widget was clicked.
Changwei Yao defined one way you can do this, but here's the way most Android programmers would do this (programmatically), since it's a little easier to read and figure out what your widgets are doing:
But first, remove the implements OnClickListener from your Activity, as it's not needed.
button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// what you want your button to do when clicked
}
}
editText.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// what you want your EditText to do when clicked
// (such as editText.setText(""))
}
}
Another way to do the same thing is to define android:onClick="insert_method_name_here" for the widgets that you want perform an action when clicked. In your case, in your main.xml (since that's what you're using in your Activity), you could write something like...
<Button android:id="#+id/testButton"
(other attributes you wish to apply to the button)
android:onClick="buttonAction" />
<EditText
(other attributes)
android:onClick="textAction" />
And then, in your Activity, you define the methods buttonAction(View v) and textAction(View v). Note that these methods must be public void, and must take the sole argument View v.
(One advantage of the XML method is that you don't necessarily have to define an android:id attribute for these widgets, unless you need to be able to manipulate them or extract information from them in your code (which means you will need to define an android:id for your EditText since you'll likely want the user's input))
If you only need to exclude the empty text field then hotveryspicy's solution is probably the quickest. For a secure solution: catching the NumberFormatException will filter anything that can not be converted to an integer.
int vis;
try {
vis = Integer.parseInt(a);
}
catch(NumberFormatException nfe) {
Log.e(TAG,"trying to convert:"+a+" to integer failed");
vis = 0;
}
The onClick never fires! Why not? Please help me.
for(int i = 0; i < 12; i++) {
String title = "Button" + i;
Button sliderButton = new Button(this);
sliderButton.setText(title);
glideMenuTray.addView(sliderButton,100,40);
sliderButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Log.d("gm", "Tapped ");
}
});
}
I'm no expert at stuff like this, but it's probably something to do with garbage collection, and the OnClickListeners passing out of scope.
Though I don't think you can use the super-easy approach to onClickListeners that Dimitar mentions, you can probably use the middle approach that the section he links to discusses, even though it's not a new approach. To repeat the example code here, it's:
View.OnClickListener handler = View.OnClickListener() {
public void onClick(View v) {
switch (v.getId()) {
case R.id.myButton: // doStuff
break;
case R.id.myOtherButton: // doStuff
break;
}
}
}
findViewById(R.id.myButton).setOnClickListener(handler);
findViewById(R.id.myOtherButton).setOnClickListener(handler);
If the only thing distinguishing the buttons is their title text, well, you could use that to distinguish between them in the master onClick method.
Also, not shure, I once had a problem like that on a TextView and it was because I didnt add setClickable(true)
My code was something like
TextView text = new TextView(this);
text.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
text.setText("***");
text.setClickable(true);
text.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//My action
}
});
myViewGroup.addView(text );
Hope this helps
If you are using Donut or Eclair, you can use common click listener, registered in your Activity and hooked with your buttons in the layout XML.
For reference, look here, the category Easier click listeners.
Am I right in assuming that the following line:
glideMenuTray.addView(sliderButton,100,40);
Adds the view to the coords x:100,y:40 onto some View extending ViewGroup?
In that case you are stacking 12 buttons on top of each other, only the last Button (labeled Button11) will be visible (and clickable).
And provided that the question is 3 years old I really hope you already resolved this by now :)
set the setOnClickListener before adding the view.
for(int i = 0; i < 12; i++) {
String title = "Button" + i;
Button sliderButton = new Button(this);
sliderButton.setText(title);
sliderButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Log.d("gm", "Tapped ");
}
glideMenuTray.addView(sliderButton,100,40);
}