Different widgets (views) for different screen orientations? - android

I'm quite new developing for Android so I have a very basic question.
Basically, I have two screen layouts, one for portrait and another for landscape orientation. I use the folders res/layout and res/layout-land. Both orientations are drawn fine, but I have different widgets (buttons) for each orientation, btnPortrait and btnLandscape.
The problem arises when I try to call onSetClickListener(). Because when the device is oriented in portrait the framework can't locate the btnLandscape and viceversa, I handle the orientation changes manually using onConfigurationChange(). It doesn't seem to work either.
My code:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnPortrait = (Button) findViewById(R.id.portraitButton);
tvPortrait = (TextView) findViewById(R.id.portraitText);
btnLandscape = (Button) findViewById(R.id.landscapeButton);
tvLandscape = (TextView) findViewById(R.id.landscapeText);
}
And the onConfigurationChange():
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){
btnPortrait.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(getContext(), "Portrait",Toast.LENGTH_SHORT).show();
}
});
}
else {
btnLandscape.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(getContext(), "Landscape", Toast.LENGTH_SHORT).show();
}
});
}
}
None of the Toasts work.
Does somebody know what could be happening?
Thanks in advance.

Don't name them differently; the widgets for the same function should share the same ID whether it's in portrait or landscape.
If it's a widget that only exists or functions differently in landscape, just check if it's null after findViewById(), and if that returns null, you know you're not in a configuration with a layout that includes that button.

Just make sure that your button Id in layout-land is same Id in default layout
Update1 :
ok add not null check before using the widget like this
if( btnPortrait !=null ) {
// do what you want
}

I'm not sure by what you mean in the comments by "they're not the same button" but a way of doing what you want with two different resource ids would be as follows...
public class MyActivity extends Activity {
Button myButton = null;
TextView myTextView = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myButton = (Button) findViewById(R.id.portraitButton);
if (myButton == null)
myButton = (Button) findViewById(R.id.landscapeButton);
myTextView = (TextView) findViewById(R.id.portraitText);
if (myTextView == null)
myTextView = (TextView) findViewById(R.id.landscapeText);
}
// The following method is your OnClickListener
public void sayHello(View v) {
switch (v.getId) {
case R.id.portraitButton :
// Do something for portrait
break;
case R.id.landscapeButton :
// Do something for landscape
break;
}
}
}
In your layout files you would then assign the OnClickListener using android:onClick as follows...
For portrait...
<Button
android:id="#+id/portraitButton"
...
android:onClick="sayHello" >
</Button>
For landscape...
<Button
android:id="#+id/landscapeButton"
...
android:onClick="sayHello" >
</Button>
In this way, the OnClickListener is set by the inflation process when setContentView(...) is called. It then simply comes down to it determining the resource id to decide what action needs to be taken.

Related

How is it possible to know which View is clicked in a layout OnClickListener?

I have a layout which contains some views. I want to set some actions when a user clicks anywhere on the layout, so I have set an OnClickListener for the layout which works as it should. But how can I know which view was clicked?
I want to assign different actions depending on the view which was clicked; or maybe no view was clicked and it was only the layout itself.
So the problem is if I set OnClickListener for one of the views, both OnCLickListeners related to the layout and the view will get activated, but I want only the view action. Thanks in advance.
Other answers are quite abstract and some are incorrect. You can't Override onClick method for an Activity as it doesn't have one (unless of course you implement an OnClickListener).
Furthermore, if you set the listener for the layout the View argument received by the onClick method will always be the layout.
You can either create your own custom layout that intercepts the clicks and check if you clicked on a view, or you can set listeners for all the views.
A somewhat cleaner solution is using a single listener and checking if it's a view that was clicked.
private final String TAG = "MainActivity";
List<View> views = new ArrayList<View>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RelativeLayout rLayout = (RelativeLayout) findViewById(R.id.relativeLayout);
TextView tv1 = (TextView) findViewById(R.id.tv1);
TextView tv2 = (TextView) findViewById(R.id.tv2);
TextView tv3 = (TextView) findViewById(R.id.tv3);
views.add(tv1);
views.add(tv2);
views.add(tv3);
View.OnClickListener clickListener = new View.OnClickListener() {
#Override
public void onClick(View v) {
boolean isView = false;
for (View view : views) {
if (v.equals(view)) {
isView = true;
break;
}
}
if (isView) {
Log.e(TAG, "Click on view");
} else {
Log.e(TAG, "Click on layout");
}
}
};
tv1.setOnClickListener(clickListener);
tv2.setOnClickListener(clickListener);
tv3.setOnClickListener(clickListener);
rLayout.setOnClickListener(clickListener);
}
If you want different actions for different views, just create a listener for each of them.
For example Layout has two views View1 and View2. I assume that you have already inflated them. So you have to set OnClickListiner for each of them
Layout.setOnClickListener(this);
View1.setOnClickListener(this);
View2.setOnClickListener(this);
Then you have to override method:
public void onClick(View v)
{
switch(v.getId())
{
case R.id.id_for_layout:
// do what you want when user click layout
break;
case R.id.id_for_first_view:
// do what you want when user click first view
break;
case R.id.id_for_second_view:
// do what you want when user click second view
break;
}
}
Remember that the method OnClick have one parameter that indicates which View is clicked!
public void onClick(View v) {
switch(v.getId()) {
case R.id.btn1:
// first button
break;
case R.id.btn2:
// second button
break;
}
}
Assign the id to each of your views by android:id="#+id/v1"
then in
onClick(View v)
check for the view like
if(v == findViewById(R.id.v1))
{
// v1 specific action
}
else if(v == findViewById(R.id.v2))
{
// v2 specific action
}
Ok, it's easy.
You have to add an OnClickListener to each view (button, textView and so on), and to the whole layout as well.
In this case, the onClickListeners that will be launched if you click are the view's onClickListener and the layout's onClickListener. So no need for a whole bunch of classes. One will be enough if you try this (do actions depending on the id and don't forget the layout ;) ):
public void onClick(View v) {
switch(v.getId()) {
case R.id.layout:
layout actions here
break;
case R.id.textview:
textview actions here
break;
this onClickListener is for all of your views ;)
There is View v parameter in onClickListner(View v) method :
#Override
protected void onCreate(Bundle savedInstanceState) {
LinearLayout layout=(LinearLayout)findViewById(R.id.linearLayout);
layout.setOnclickListener(this);
}
#Override
public void onClick(View v) {
if (v.getId() == R.id.linearLayout){
//your logic
}
}
for anyone interested you can also log the currently clicked view:
getActivity()
.getWindow()
.getDecorView()
.findViewById(android.R.id.content)
.setOnTouchListener((v, event) -> {
if (event.getAction() == MotionEvent.ACTION_UP) {
Log.v("[onClick]", v.getClass().getCanonicalName());
}
return false;
});

CheckBoxes in ListView disappear when the screen rotates

What my application first does is it loads ListView whose items have invisible CheckBoxes by setting its visibility View.Gone. When the user tabs a menu button then it will turn on and off the CheckBox visibility and some other layouts. Below is the code, I removed some unnecessary parts:
private void editmodeSwitch(boolean flag){
// get topbar, bottombar, and bottombar2
LinearLayout topbar = (LinearLayout) findViewById(R.id.task_topbar_linearLayout);
LinearLayout bottombar = (LinearLayout) findViewById(R.id.task_bottombar1_linearlayout);
LinearLayout bottombar2 = (LinearLayout) findViewById(R.id.task_bottombar2_linearlayout);
if(flag){
isEditmodeOn = true;
// make topbar and bottombar2 visilble, but bottombar gone
topbar.setVisibility(View.VISIBLE);
bottombar.setVisibility(View.GONE);
bottombar2.setVisibility(View.VISIBLE);
// make checkboxes visible in listview visible as well
for(int i=0; i<listView.getChildCount(); i++){
LinearLayout ll = (LinearLayout) listView.getChildAt(i);
CheckBox cb = (CheckBox) ll.findViewById(R.id.task_row_checkBox1);
cb.setVisibility(View.VISIBLE);
}
}
else{
isEditmodeOn = false;
topbar.setVisibility(View.GONE);
bottombar.setVisibility(View.VISIBLE);
bottombar2.setVisibility(View.GONE);
// set each checkbox false and its visibility gone
for(int i=0; i<listView.getChildCount(); i++){
LinearLayout ll = (LinearLayout) listView.getChildAt(i);
CheckBox cb = (CheckBox) ll.findViewById(R.id.task_row_checkBox1);
cb.setVisibility(View.GONE);
cb.setChecked(false);
}
}
}
It works fine but the problem is the application doesn't work when the screen rotates(changes the screen orientation). Everything worked fine as it displayed some layouts but only CheckBoxes in list items. Below is the code inonCreate()`:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.task_layout);
initialize();
loadDB();
updateListAdapter(list_title, list_date);
// in case of screen rotation
if(savedInstanceState != null){
isEditmodeOn = savedInstanceState.getBoolean(EDITMODE_CHECK);
isItemChecked = savedInstanceState.getBoolean(ITEM_CHECK);
if(isEditmodeOn){
if(!isItemChecked){
Log.i(tag, "item NOT checked");
editmodeSwitch(true);
} else{
//this is something different so please don't mind
deditmodeSwitch(savedInstanceState.getBooleanArray(LIST_CB_CHECK));
}
}
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
// save values for rotation
outState.putBoolean(EDITMODE_CHECK, isEditmodeOn);
outState.putBoolean(ITEM_CHECK, isItemChecked);
outState.putBooleanArray(LIST_CB_CHECK, list_cb_check);
}
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
Log.i(tag, "you're in onRestoreInstanceState()");
// in case of screen rotation
if(savedInstanceState != null){
isEditmodeOn = savedInstanceState.getBoolean(EDITMODE_CHECK);
isItemChecked = savedInstanceState.getBoolean(ITEM_CHECK);
if(isEditmodeOn){
if(!isItemChecked){
Log.i(tag, "item NOT checked");
editmodeSwitch(true);
} else{
// this is for something else so please ignore this part
editmodeSwitch(savedInstanceState.getBooleanArray(LIST_CB_CHECK));
}
}
}
What I guessed is the ListView is being loaded at the end. Therefore, even if the code in onCreate() makes CheckBoxes visible, the CheckBoxes will become invisible again as its initialization in xml will do so. However, I'm stuck here and need your advice to solve this problem. Can anyone help me?
Just in case, below is the checkbox code of layout xml file for getview.
<CheckBox android:id="#+id/task_row_checkBox1" android:gravity="right"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:visibility="gone"
/>
Override onSaveInstanceState for saving value on screen rotation and onRestoreInstanceState as:
protected void onCreate(Bundle savedInstanceState) {
if(null != savedInstanceState)
{
Boolean IntTest = savedInstanceState.getBoolean("ITEM_CHECK");
Boolean StrTest = savedInstanceState.getBoolean("ITEM_CHECK");
Log.e(TAG, "onCreate get the savedInstanceState+IntTest="+IntTest+"+StrTest="+StrTest);
}
}
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
// Save away the CheckBoxes states, so we still have it if the activity
// needs to be killed while paused.
savedInstanceState.putBoolean(EDITMODE_CHECK, 0);
savedInstanceState.putBoolean(ITEM_CHECK, 0);
super.onSaveInstanceState(savedInstanceState);
Log.e(TAG, "onSaveInstanceState");
}
#Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
Boolean IntTest = savedInstanceState.getBoolean(EDITMODE_CHECK);
Boolean StrTest = savedInstanceState.getBoolean(ITEM_CHECK);
Log.e(TAG, "onRestoreInstanceState+IntTest="+IntTest+"+StrTest="+StrTest);
}
Similar to how you override onCreate, you can override onConfigurationChanged(...) which you can setup to run when the screen changes orientation.
In order for OnConfigurationChanged(...) to be trigger when the screen rotates, you need to to edit your manifest and put that relationship/rule in.
It's easy to do but takes a bit of explaining and it was answered before in this question:
Activity restart on rotation Android
Edit: Here is the dev guide on how to handle configuration changes
http://developer.android.com/guide/topics/resources/runtime-changes.html
Edit #2: First, let me suggest using Imran's solution. It follows the Developer Guide better and the end results will be the same.
Now, for the onConfigurationChanged solution.
Look at what you are doing with your onCreate:
1) Set the view. (Checkboxes are hidden at this point. Right?)
2) Call your DB and determine if you should display checkboxes (edit mode)
3) Make all the checkboxes visible.
Now, onConfigurationChanged also calls setContentView, at which point all your checkboxes are hidden again. So you need to repeat the process of making your checkboxes visible (#3 above). You probably don't need to repeat step #2 because the value should be retained, but I'm not sure how the logic of your app works, so you may need to re-do step #2.
Does that make sense?
Based on my experience, getview seems to be triggered at the end and it was why 'onRestoreInstanceState()' and 'onConfigurationChanged()' could not make it as getview will reset my checkboxes invisible as initialization in the layout xml file.
Therefore, the only solution I could find out was I must control them in getview for the answer.

<ToggleButton> onClickListener - Create/Delete button + add content to button

I have this problem with my ToggleButton.
I want it to create/delete a button upon being toggled, and at the same time add content/functions to the button, like drawable and such.
This is the current code:
public class BillardScoreboardActivity extends Activity {
/** Called when the activity is first created. */
Button minuskegle, minuskugle, pluskugle, pluskegle, plusmidkegle, minusmidkegle, miss;
ToggleButton toggle;
LinearLayout bottomlayout;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
toggle = (ToggleButton) findViewById(R.id.bRedGreen);
toggle.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
pluskugle = (Button) findViewById(R.id.bBallhole);
minuskugle = (Button) findViewById(R.id.bBallhole);
pluskegle = (Button) findViewById(R.id.bKegle);
minuskegle = (Button) findViewById(R.id.bKegle);
plusmidkegle = (Button) findViewById(R.id.bKeglemid);
minusmidkegle = (Button) findViewById(R.id.bKeglemid);
bottomlayout = (LinearLayout) findViewById(R.id.bottomlayout);
miss = (Button) findViewById(R.id.bMiss);
if(toggle.isChecked())
{
minuskugle.setBackgroundResource(R.drawable.redballinhole);
minuskegle.setBackgroundResource(R.drawable.redkegle);
minusmidkegle.setBackgroundResource(R.drawable.midkegleminus);
miss.setBackgroundResource(R.drawable.missbutton);
miss.setVisibility(View.VISIBLE);
}
else
{
pluskugle.setBackgroundResource(R.drawable.whiteballinhole);
pluskegle.setBackgroundResource(R.drawable.kegleb);
plusmidkegle.setBackgroundResource(R.drawable.midkegleplus);
miss.setVisibility(View.GONE);
}
}
});
}
The current problem is that it can't find the (buttontest) in this part of the code:
else
{
pluskugle.setBackgroundResource(R.drawable.whiteballinhole);
pluskegle.setBackgroundResource(R.drawable.kegleb);
plusmidkegle.setBackgroundResource(R.drawable.midkegleplus);
bottomlayout.removeView(buttontest);
}
And as mentioned earlier, the second problem is to make the button inherit some functions/content.
for bigger version: http://i.imgur.com/KxKvh.png
Btw... Everytime i start up the application, it gives me 2 apps to choose between, whereof only the bottom one works:
I guess the problem is that the togglebutton's initial state is 'checked'. That means when you click it the first time, isChecked() will return false and the else-part of your code will be executed. But at that point, buttontest hasn't been added to bottomlayout yet.
I recommend you to have the button inside the layout by default and call buttontest.setVisibility(View.GONE) when you would like to hide it and buttontest.setVisibility(View.VISIBLE) when it needs to be shown.
As for your second question, just call setBackgroundResource/Drawable to add content (like you're already doing it with the other buttons). If you say you want to add functionality, I assume you intend to do something when the button is clicked? If yes, add a View.OnClickListener.
Hope I could help you.

How to give an argument to a function using android xml?

I have an app with a lot of buttons (more than 300)
i want to know if there is a way to use android:onClick="function" with an arguments in my layout xml
because im too lazy to make a function for each button, and i want to do somenthin like
public void allbuttons(View view, String stringa) {
if stringa = 1 { bla bla bla}
elif stringa = 2 { blachos}
}
you get the idea
Give an id to each of your button.
In your common handler, just check the ((Button)view).getId() for the id in a switch (with the latest adk, you have to use if-else) and handle it differently in each case.
public class MyButtonClickHandler implements View.OnClickListener {
#Override
public void onClick(View v) {
Button button = (Button) v;
if (button.getId() == R.id.button1) {
Toast.makeText(Sample1Activity.this, "Toast1", 1000).show();
} else if (button.getId() == R.id.button2) {
Toast.makeText(Sample1Activity.this, "Toast2", 1000).show();
}
}
}
and in your onCreate of activities you can add
Button button1 = (Button) findViewById(R.id.button1);
button1.setOnClickListener(new MyButtonClickHandler());
I am adding function reference in the code but you can do it in xml file too.

ParseInt Exception

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;
}

Categories

Resources