I want to be able to respond to a click event on a disabled switch, is that possible?
I have a switch that is not enabled until the user fills in some information, so it looks like this:
I want to prompt the user to fill out the information if they click on the disabled switch with a dialog, like so:
mySwitch.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (!userInfo.isFilled){
new AlertDialog.Builder(MainActivity.this)
.setTitle("Fill out info first!")
.setMessage("You must first fill out info before turning on this featurel")
.setNeutralButton("Okay", null)
.show();
}
}
});
However, the onClick() is not triggered when I click on the disabled switch, so how do I get when the user clicks on it?
You could place a transparent View on top of the Switch and toggle its enabled state opposite the Switch, and show the message when this overlaid View is clicked.
From the View.java source code,
public boolean dispatchTouchEvent(MotionEvent event) {
// If the event should be handled by accessibility focus first.
if (event.isTargetAccessibilityFocus()) {
// We don't have focus or no virtual descendant has it, do not handle the event.
if (!isAccessibilityFocusedViewOrHost()) {
return false;
}
// We have focus and got the event, then use normal event dispatch.
event.setTargetAccessibilityFocus(false);
}
boolean result = false;
if (mInputEventConsistencyVerifier != null) {
mInputEventConsistencyVerifier.onTouchEvent(event, 0);
}
final int actionMasked = event.getActionMasked();
if (actionMasked == MotionEvent.ACTION_DOWN) {
// Defensive cleanup for new gesture
stopNestedScroll();
}
if (onFilterTouchEventForSecurity(event)) {
//noinspection SimplifiableIfStatement
ListenerInfo li = mListenerInfo;
if (li != null && li.mOnTouchListener != null
&& (mViewFlags & ENABLED_MASK) == ENABLED
&& li.mOnTouchListener.onTouch(this, event)) {
result = true;
}
if (!result && onTouchEvent(event)) {
result = true;
}
}
if (!result && mInputEventConsistencyVerifier != null) {
mInputEventConsistencyVerifier.onUnhandledEvent(event, 0);
}
// Clean up after nested scrolls if this is the end of a gesture;
// also cancel it if we tried an ACTION_DOWN but we didn't want the rest
// of the gesture.
if (actionMasked == MotionEvent.ACTION_UP ||
actionMasked == MotionEvent.ACTION_CANCEL ||
(actionMasked == MotionEvent.ACTION_DOWN && !result)) {
stopNestedScroll();
}
return result;
}
the enabled flag ensures the UnhandledEvents are consumed however not passed along to the listeners,thereby bypassing all your possible code.So it is not possible to listen to events on a disabled view.
That said, your options are,
Change the style to mimic that of a disabled view as mentioned here,and then add your required functionality.
Add a overlay invisible view to perform your required functionality which you can set to Gone once the view should be enabled.
Use something apart from enabled,(you could setClickable(false) and consume touch events)
You can set onTouchListener and react to boolean (e.g isToggleEnable) reference with respect to the user's previous actions:
mySwitch.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if(!isToggleEnable){
//Taost here
}
//If isToggleEnable = false on return OnClickListener won't be called
return isToggleEnable;
}
});
When it is disabled, setEnabled(false), these listeners won't work.
Try this way: don't disable it, use the setOnCheckedChangeListener and check against your is-entry-filled in there:
use setOnCheckedChangeListener
switch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (!isEntryFilled) {
buttonView.setChecked(false);
// your alert dialog
} else {
}
}
});
this will re-check it back to off and pop your alert, until isEntryFilled is met.
EDIT
OR instead of setEnabled(false), use setClickable(false) or android:clickable="false" since docs say setClickable() is tied to click-events.
and instead of OnClickListener, try OnTouchListener. It will register your on-down-touch (and ignore your on-up-touch), since a click consists of down+up.
switch.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (!isEntryFilled) {
buttonView.setChecked(false);
// your alert dialog
}
return false;
}
});
then somewhere else, where you check for isEntryFilled, reactivate your switch with switch.setClickable(true)
Try setting setFocusable(false) and setEnabled(true) on your switch. That way, click events will be fired while the switch still being "disabled". Taken from this answer.
mySwitch.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (isClick()){
//Your Valid Code
}else{
//Make our switch to false
new AlertDialog.Builder(MainActivity.this)
.setTitle("Fill out info first!")
.setMessage("You must first fill out info before turning on this featurel")
.setNeutralButton("Okay", null)
.show();
}
}
});
public Boolean isClick(){
//check condition that user fill details or not
//if yes then return true
// else return false
}
Let the Parent View intercept ClickEvents or TouchEvents, when its detected check if the receiving View is disabled, and do what you have to do.
Edit
"it doesn't work when disabled?"
try these codes, Im use LinearLayout for easy aligment. but overall it should give you an example
this is a full example
XML
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="70dp"
android:background="#273746">
<FrameLayout
android:layout_width="match_parent"
android:id="#+id/ass"
android:background="#drawable/abc_popup_background_mtrl_mult"
android:layout_height="match_parent">
</FrameLayout>
MainActivity onCreate
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_entry_screen);
FrameLayout fl = (FrameLayout)findViewById(R.id.ass);
Test t = new Test(this);
FrameLayout.LayoutParams lp = (LayoutParams) fl.getLayoutParams();
lp.height = LayoutParams.MATCH_PARENT;
lp.width = LayoutParams.MATCH_PARENT;
t.setOrientation(LinearLayout.VERTICAL);
t.setLayoutParams(lp);
fl.addView(t);
t.setBackgroundColor(Color.YELLOW);
Button b = new Button(this);
b.setText("patricia");
t.addView(b);
b = new Button(this);
b.setText("monica");
t.addView(b);
b = new Button(this);
b.setText("rebecca");
t.addView(b);
}
Test.java
public class Test extends LinearLayout {
public Test(Context context) {
super(context);
}
#Override
public boolean onInterceptTouchEvent(MotionEvent event) {
StringBuilder sb = new StringBuilder();
sb.append("intercept \n\r");
int x = (int)event.getX(),
y= (int)event.getY();
for(int i =0; i< getChildCount(); i++){
int[] pos = new int[]{getChildAt(i).getLeft(),getChildAt(i).getTop(),
getChildAt(i).getMeasuredWidth(),
getChildAt(i).getMeasuredHeight()};
sb.append(getChildAt(i).getLeft()+", ");
sb.append(getChildAt(i).getTop()+", ");
sb.append(getChildAt(i).getMeasuredWidth()+", ");
sb.append(getChildAt(i).getMeasuredHeight());
sb.append("\n\r");
sb.append(isInBounds(pos, x, y));
sb.append("\n\r");
}
sb.append("x is ");
sb.append(x);
sb.append("y is ");
sb.append(y);
Toast.makeText(getContext(),sb.toString() , Toast.LENGTH_LONG).show();
return super.onInterceptTouchEvent(event);
}
private boolean isInBounds(int[] dimen, int x, int y){
return ((x >= dimen[0] && x < (dimen[0] + dimen[2]))
&& (y >= dimen[1] && y < (dimen[1] + dimen[3])));
}
}
Now The one you click will check out to be true, that is the child, now when it checks out to be true you can do something like this
View v = getchildAt(pos);
//its the one that is tapped or clicked
if(!v.isEnabled()){
//this is the guy you want now, do what you want to do
for click event i am not try this, but you could just do View.performClick() or put your Dialog in the ViewGroup class and call it
actually you could use the View..getClipBounds() to save yourself from int array
Set the disable switches on click listener to change the listeners of the other switches. For example:
Switch s = (Switch) findViewById(R.id.SwitchID);
if (s != null) {
s.setOnCheckedChangeListener(this);
}
/* ... */
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
Toast.makeText(this, "The Switch is " + (isChecked ? "on" : "off"),
Toast.LENGTH_SHORT).show();
if(isChecked) {
//do stuff when Switch is ON
//this is where you set your normal state OnClickListner
} else {
mySwitch.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (!userInfo.isFilled){
new AlertDialog.Builder(MainActivity.this)
.setTitle("Fill out info first!")
.setMessage("You must first fill out info before turning on this featurel")
.setNeutralButton("Okay", null)
.show();
}
}
});
}
}
I'm guessing you've disabled the switch using switch.setEnabled(false). If so, the onclick event will not trigger. If you still want to handle a click action when the switch is disabled, you can use .setOnTouchListener()...
You're best bet however would be to use .setOnCheckedChangeListener() and keeping the switch enabled. Basically when onCheckChanged() gets called, you can popup your dialog if the switch value is on and when the user click ok, you default the switch back to off.
mSwitched.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
if (checked && !userInfo.isFilled){
new AlertDialog.Builder(Activity.this)
.setTitle("Fill out info first!")
.setMessage("You must first fill out info before turning on this featurel")
.setNeutralButton("Okay", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
mSwitched.setChecked(false);
}
})
.show();
}
}
});
You can do this in a different way,Give a root layout to toggle button with same width and height of toggle button
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<!--Root layout to toggle button with same height and width
of toggle button-->
<LinearLayout
android:layout_width="wrap_content"
android:id="#+id/linear"
android:layout_height="wrap_content">
<ToggleButton
style="?android:attr/buttonStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/button"
/>
</LinearLayout>
</RelativeLayout>
When you disable the button,make the button as not focasable and clickable .Then os will handover touch functionality to rootlayout.In the root layout click listner we can write the click logic when the button is not enabled
public class MainActivity extends AppCompatActivity {
ToggleButton button;
LinearLayout linearLayout;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button= (ToggleButton) findViewById(R.id.button);
linearLayout= (LinearLayout) findViewById(R.id.linear);
//disabling button
button.setEnabled(false);
button.setClickable(false);
button.setFocusableInTouchMode(false);
button.setFocusable(false);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//write the logic here which will execute when button is enabled
}
});
linearLayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//write the logic here which will execute when button is disabled
}
});
}
}
When you enable the button,make button to clickable and focausable.
//enabling button
button.setEnabled(true);
button.setClickable(true);
button.setFocusableInTouchMode(true);
button.setFocusable(true);
Related
I know that was already asked but it is outdated:
I have 2 buttons that represent 2 choices and if one is selected the background color gets changed to yellow. But if i want to change the choice i need to somehow reset the button:
I already try to set it back but some old design comes out. Can you provide me the id of the modern button style? And show me how to implement it?
int myChoice;
if (view == findViewById(R.id.choice1)){
myChoice = 1;
choice1.setBackgroundColor(getResources().getColor(R.color.highlightButton));
choice2.setBackgroundResource(android.R.drawable.btn_default);
}
else if (view == findViewById(R.id.choice2)){
myChoice = 2;
choice2.setBackgroundColor(getResources().getColor(R.color.highlightButton));
choice1.setBackgroundResource(android.R.drawable.btn_default);
}
}
Use Tags with getBackground(). This will assure you are always setting back to original.
Add following in beginning of function
if (v.getTag() == null)
v.setTag(v.getBackground());
Then instead of setBackgroundResource, use
v.setBackground(v.getTag());
Starting from here, you can store the default color of the button into a Drawable and grab the selection color (Yellow in your case) into anther Drawable, then toggle background colors of buttons with these Drawable variables
please check below demo
public class MainActivity extends AppCompatActivity {
private Drawable mDefaultButtonColor;
private Drawable mSelectedButtonColor;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final Button btn1 = findViewById(R.id.btn1);
final Button btn2 = findViewById(R.id.btn2);
mDefaultButtonColor = (btn1.getBackground());
mSelectedButtonColor = ContextCompat.getDrawable(this, R.color.buttonSelected);
btn1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
toggleButton(btn1, true);
toggleButton(btn2, false);
}
});
btn2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
toggleButton(btn1, false);
toggleButton(btn2, true);
}
});
}
private void toggleButton(Button button, boolean isSelected) {
button.setBackground(isSelected ? mSelectedButtonColor : mDefaultButtonColor);
}
}
I want to achieve the following abilities:
Select only one child View inside a GridLayout each time by long clicking it.
A click on the GridLayout or any ancestor parent in the visual hierarchy will deselected selected child View if one already selected.
The problem is when when registering a View.OnLongClickListener callback to child View, neither parent GridLayout nor any ancestor registered callbacks (either View.OnClickListener or View.onTouchEvent) called when clicking on them.
How can I get a selected child inside a GridLayout similar to either AdapterView.OnItemSelectedListener or AdapterView.OnItemLongClickListener and solve the above mentioned problem?
What about storing a "selected" view as a global variable, and removing it when its focus changes? By playing with focusable, focusableInTouchMode and onClick listeners, you could have the right results. I'm not sure that's the best solution, but it works.
What you will need:
A global View variable: the GridLayout's child long clicked, as selected.
(optional) A custom parent container as any ViewGroup: it will set the focusable listeners on all its children [*]. In my tests, I used a LinearLayout and a RelativeLayout.
[*] If you don't use the optional parent custom Class, you have to set android:focusable="true" and android:focusableInTouchMode="true" on all children of the parent ViewGroup. And you'll have to set OnClickListener in order to call removeViewSelected() when the parent ViewGroup is clicked.
Adding Click listeners for GridLayout children: which updates the selected view.
Implementing a Focus listener: which removes the selected view if it's losing focus.
It will handle all focus change state on parent and child hierarchy, see the output:
I used the following pattern:
CoordinatorLayout --- simple root group
ParentLayout --- aka "parentlayout"
Button --- simple Button example
GridLayout --- aka "gridlayout"
FloattingActionButton --- simple Button example
Let's preparing the selected View and its update methods in the Activity:
private View selectedView;
...
private void setViewSelected(View view) {
removeViewSelected();
selectedView = view;
if (selectedView != null) {
// change to a selected background for example
selectedView.setBackgroundColor(
ContextCompat.getColor(this, R.color.colorAccent));
}
}
private View getViewSelected() {
if (selectedView != null) {
return selectedView;
}
return null;
}
private void removeViewSelected() {
if (selectedView != null) {
// reset the original background for example
selectedView.setBackgroundResource(R.drawable.white_with_borders);
selectedView = null;
}
// clear and reset the focus on the parent
parentlayout.clearFocus();
parentlayout.requestFocus();
}
On each GridLayout child, add the Click and LongClick listeners to update or remove the selected view. Mine were TextViews added dynamically, but you could easily create a for-loop to retrieve the children:
TextView tv = new TextView(this);
...
gridlayout.addView(tv);
tv.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
removeViewSelected();
}
});
tv.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View view) {
setViewSelected(view);
return true;
}
});
Set the FocusChange listener on the parent container:
parentlayout.setOnFocusChangeListener(new View.OnFocusChangeListener() {
#Override
public void onFocusChange(View view, boolean hasFocus) {
View viewSelected = getViewSelected();
// if the selected view exists and it lost focus
if (viewSelected != null && !viewSelected.hasFocus()) {
// remove it
removeViewSelected();
}
}
});
Then, the optional custom ViewGroup: it's optional because you could set the focusable state by XML and the clickable listener dynamically, but it seems easier to me. I used this following custom Class as parent container:
public class ParentLayout extends RelativeLayout implements View.OnClickListener {
public ParentLayout(Context context) {
super(context);
init();
}
public ParentLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public ParentLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
// handle focus and click states
public void init() {
setFocusable(true);
setFocusableInTouchMode(true);
setOnClickListener(this);
}
// when positioning all children within this
// layout, add their focusable state
#Override
protected void onLayout(boolean c, int l, int t, int r, int b) {
super.onLayout(c, l, t, r, b);
final int count = getChildCount();
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
child.setFocusable(true);
child.setFocusableInTouchMode(true);
}
// now, even the Button has a focusable state
}
// handle the click events
#Override
public void onClick(View view) {
// clear and set the focus on this viewgroup
this.clearFocus();
this.requestFocus();
// now, the focus listener in Activity will handle
// the focus change state when this layout is clicked
}
}
For example, this is the layout I used:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout ...>
<com.app.ParentLayout
android:id="#+id/parent_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal">
<Button
android:id="#+id/sample_button"
android:layout_width="250dp"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_alignParentBottom="true"
android:text="A Simple Button"
android:layout_marginTop="20dp"
android:layout_marginBottom="20dp"/>
<android.support.v7.widget.GridLayout
android:id="#+id/grid_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerHorizontal="true"
android:layout_above="#id/sample_button" .../>
</com.app.ParentLayout>
<android.support.design.widget.FloatingActionButton .../>
</android.support.design.widget.CoordinatorLayout>
Hope this will be useful.
Use the following code :
int last_pos = -1;
GridLayout gridLayout;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
gridLayout = (GridLayout) findViewById(R.id.gridLayout);
int child_count = gridLayout.getChildCount();
for(int i =0;i<child_count;i++){
gridLayout.getChildAt(i).setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View view) {
//Deselect previous
if(last_pos!=-1) gridLayout.getChildAt(last_pos).setSelected(false);
//Select the one you clicked
view.setSelected(true);
last_pos = gridLayout.indexOfChild(view);
return false;
}
});
}
//Remove focus if the parent is clicked
gridLayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
gridLayout.getChildAt(last_pos).setSelected(false);
}
});
I have declared my variable, 'changed' too null so that I can check if it changes when the edittext is changed,
The problem I think is, when I press either the save button or the cancel button, it will always produce the value null, as upon clicking the button it is still null. However, I thought that the textwatcher would listen to the EditText and even if nothing was changed in the EditText it would by default change the SetChanged() to false as it provided "live updates", however clearly this isn't the case, am I doing something wrong? or am I supposed to approach it in a different way?, is there some way of refreshing it?
Advise would be greatly appreciated.
(P.S Some code was deleted to reduce the size and make it look easy on the eye, so excuse me for any missing braces. Furthermore, the activity does run properly as it shows the layout.However upon pressing any of the buttons it causes it to crash.)
public class EditNewItemActivity extends AppCompatActivity{
private Boolean changed = null;
private TextView title,content;
private Button saveBtn,cancelBtn;
private String date;
private int id;
#Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_edit_item);
title = (TextView) findViewById(R.id.editItemTitle);
content = (TextView) findViewById(R.id.editItemDescription);
saveBtn = (Button) findViewById(R.id.editItemSaveBtn);
cancelBtn = (Button) findViewById(R.id.editItemCancelBtn);
Bundle extras = getIntent().getExtras();
title.setText(extras.getString("title"));
content.setText(extras.getString("content"));
date = extras.getString("date");
id = extras.getInt("id");
GenericTextWatcher textWatcher = new GenericTextWatcher();
title.addTextChangedListener(textWatcher);
content.addTextChangedListener(textWatcher);
ClickEvent clickEvent = new ClickEvent();
saveBtn.setOnClickListener(clickEvent);
cancelBtn.setOnClickListener(clickEvent);
}
private class ClickEvent implements View.OnClickListener{
#Override
public void onClick(View v) {
switch (v.getId()){
case R.id.editItemSaveBtn:
save();
break;
case R.id.editItemCancelBtn:
cancel();
break;
}
}
}
private void cancel() {
if (getChanged() == null){
//This was used to simply verify that getchanged was still null.
}
if (title.getText().toString() != "" || content.getText().toString() != ""){
if (getChanged() == false) {
// if nothing has been changed let it cancel etc
}else {
}
}
}
private void save() {
if (tempTitle != "" || tempContent != "") {
if(getChanged() == true){
}
}
public Boolean getChanged() {
return changed;
}
public void setChanged(Boolean changed) {
this.changed = changed;
}
private class GenericTextWatcher implements TextWatcher{
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
Log.v("Beforetext:", s.toString());
EditNewItemActivity editItem = new EditNewItemActivity();
editItem.setChanged(false);
}
#Override
public void afterTextChanged(Editable s) {
Log.v("afterTextChanged:", s.toString());
EditNewItemActivity editItem = new EditNewItemActivity();
editItem.setChanged(true);
Log.v("Status:", editItem.getChanged().toString());
}
}
You had change the changed. But which you changed is in your new EditNewItemActivity not in your current page.
This is where you made mistake (beforeTextChanged and afterTextChanged in your GenericTextWatcher):
EditNewItemActivity editItem = new EditNewItemActivity();
editItem.setChanged(false); //or true
You should just call:
setChanged(false); // or true
In fact, you should not new an activity yourself, activity must be create by the Android Framework so that it can be managed by the system.
Right now I have a save button that I want to show only if all the views inside a viewpager are shown. That means that when the user swipes between views and have seen all views inside a viewpager, then show a save button.
I want to show the save button on every view when they have seen all views hereby after.
The trouble I am having is how to set up the logic. I started out with setting the save button invisible until the last view of the viewpager. On the last view of the viewpager, show the save button. But the problem is when the user goes to the last view (there's a save button) and then goes back to a previous view, the save button is gone.
So, I was wondering how can I show the save button permanently on all views after the user has seen all views?
Here's what I have so far:
I have this snippet inside my InstantiateItem() :
if(isViewed)
{
save_button.setVisibility(Button.VISIBLE);
System.out.println("Is this called? isViewed = true");
}else if (position == numberOfPages.size()-1) {
isViewed = true;
save_button.setVisibility(Button.VISIBLE);
}
where
#Override
public void onPageSelected(int position) {
isViewed = true;
}
EDIT:
I tried the following solutions but with no luck.
Button save_button = (Button) findViewById(R.id.save);
if(isViewed[position])
{
save_button.setVisibility(Button.VISIBLE);
}
if (position == numberOfPages.length-1 && !isViewed[position]) {
isViewed[position] = true;
save_button.setVisibility(Button.VISIBLE);
}
isViewed[position] =true;
And
isViewed[position] = true;
if (isViewed[position] == isViewed[numberOfPages.length-1]) {
save_button.setVisibility(Button.VISIBLE);
}
if (isViewed[position]) {
save_button.setVisibility(Button.VISIBLE);
} else {
save_button.setVisibility(Button.INVISIBLE);
}
In your onPageSelected, do the following
if(isViewed)
{
save_button.setVisibility(Button.VISIBLE);
}
if (position == numberOfPages.size()-1) {
isViewed = true;
save_button.setVisibility(Button.VISIBLE);
}
Note the above are two seperate if statements.
Make your isViewed global and default to false.
boolean []isViewed = new boolean[noOfPages.size()];
#Override
public void onPageSelected(int position) {
if(isViewed[position])
{
save_button.setVisibility(Button.VISIBLE);
}
else {
save_button.setVisibility(Button.GONE);
}
isViewed[position] = true;
}
I've searched long and far and found a few different ways people are dealing with removing a single and often specific tab from a TabHost object. I would like to try, if I may, to gather all those methods to this single question so that people my "shop" for the right method they need and hopefully get the answer they need to write their code; I also feel that it will cut down on the number of these questions.
At the moment I'm having trouble finding a solution to my code as well. I'm attempting to get rid of a particular tab without touching the others; hopefully I too will find my answer.
I wont pick a particular answer for this question for a while, so please just list the method you used to deal with this problem here for others to see.
Thank you.
Update:
Okay, here is my current code:
TabHost mTabHost;
TabHost.TabSpec spec;
Intent mSettingsIntent;
Intent mSearchIntent;
int tabNum = 1;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mSearchIntent = new Intent().setClass(this, SearchTab.class);
mTabHost = getTabHost();
mTabHost.getTabWidget().setDividerDrawable(R.drawable.tab_divider);
makeTab("Tab");
final Button newSearchBtn = (Button) findViewById(R.id.new_search_btn);
newSearchBtn.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
// Perform action on clicks
EditText searchBar = (EditText) findViewById(R.id.search_bar);
final String searchString = searchBar.getText().toString();
makeTab(searchString);
}
});
final EditText edittext = (EditText) findViewById(R.id.search_bar);
edittext.setOnKeyListener(new OnKeyListener() {
public boolean onKey(View v, int keyCode, KeyEvent event) {
// If the event is a key-down event on the "enter" button
if ((event.getAction() == KeyEvent.ACTION_DOWN) &&
(keyCode == KeyEvent.KEYCODE_ENTER)) {
// Perform action on key press
EditText searchBar = (EditText) findViewById(R.id.search_bar);
final String searchString = searchBar.getText().toString();
makeTab(searchString);
return true;
}
return false;
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.tab_menu, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle item selection
switch (item.getItemId()) {
case R.id.menu_close:
// TODO: Find/define method to close a single tab
closeTab();
return true;
case R.id.menu_settings:
// TODO: Create a basic Settings Activity and call constructor here
return true;
default:
return super.onOptionsItemSelected(item);
}
}
public void makeTab(String tabText) {
String tabTag = "Tab" + tabNum++;
View tabview = createTabView(mTabHost.getContext(), tabText);
spec = mTabHost.newTabSpec(tabTag).setIndicator(tabview).setContent(new Intent().setClass(this, SearchTab.class));
mTabHost.addTab(spec);
mTabHost.setCurrentTabByTag(tabTag);
}
private void closeTab() {
// TODO: Define method for closing a single tab with tabTag
mTabHost.removeViewAt(mTabHost.getCurrentTab());
}
private static View createTabView(final Context context, final String text) {
View view = LayoutInflater.from(context).inflate(R.layout.tabs_bg, null);
TextView tv = (TextView) view.findViewById(R.id.tabsText);
tv.setText(text);
return view;
}
}
My app locks up due to a NullPointer Exception I'm not sure why; I'm still trying to figure out how to read the debugger perspective in Eclispe for clues. I'll update when I have more.