I need to detect when a TextView is made visible and when its made invisible. Is there any way to do this in Android? I've to make some processing when a TextView in my application changes visibility. Actually, it's visibility is being updated at a number of places and I'm looking to avoid calls at all of these places.
I don't know if this will answer your question, but if you want to listen to textview visibility changes, I suggest customizing TextView and implement your own listener for it.
public class TextViewExtension extends TextView {
protected OnVisibilityChange mChangeListener = null;
public interface OnVisibilityChange {
void onChange(TextViewExtension mTextView, int mPrevVisibility, int mNewVisibility);
}
public TextViewExtension(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
/* (non-Javadoc)
* #see android.view.View#setVisibility(int)
*/
#Override
public void setVisibility(int visibility) {
// TODO Auto-generated method stub
super.setVisibility(visibility);
if (mChangeListener != null) {
mChangeListener.onChange(this, getVisibility(), visibility);
}
}
public void setOnVisibilityChange(OnVisibilityChange mChangeListener) {
this.mChangeListener = mChangeListener;
}
}
Here are examples for further implementation if you are curious
Hope it helps :)
visibility="gone"
in your xml fil
static boolean textviewon=false;
if(textviewon){
textview.setvisibility(View.Visible);
}else
textview.setvisibility(View.Invisible);
put above condition in your code
Related
I've read through a lot of questions on how to update a ListView. They all pretty much say adapter.notifyDataSetChanged() (if in a seperate thread with runOnUiThread).
My problem starts a bit earlier: How do I even get the Adapter I need or for that matter an Activity to call runOnUiThread?
Here is a very simplified version of my current code:
I have a class for the Data, which can be updated from anywhere at any time. The update method needs to start a new Thread, which is why I can't simply wait for a return value.
class Data {
private static double[] data = new double[7]
public static void update(final Context context) {
new Thread(new Runnable() {
#Override
public void run() {
//do lots of complicated stuff
}
}).start();
}
public double[] getData {
return data;
}
I have an Activity (not the main Activity) that, among other stuff, contains the ListView
public class ListViewActivity extends ActionBarActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_ListView);
ListView listView = (ListView) findViewById(R.id.MyListView);
listView.setAdapter(new CustomListViewAdapter(this));
}
I then use a custom Adapter to set up the ListView how I want it.
class CustomListViewAdapter extends BaseAdapter {
private final LayoutInflater layoutInflater;
public CustomListViewAdapter(Context context) {
layoutInflater = LayoutInflater.from(context);
}
#Override
public View getView(int position, View view, ViewGroup parent) {
ViewHolder viewHolder = new ViewHolder();
if (view == null) {
view = layoutInflater.inflate(R.layout.listView_row_layout, parent, false);
viewHolder.value = (TextView) view.findViewById(R.id.listViewDataTextField);
view.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) view.getTag();
}
double data = Data.getData()[position];
viewHolder.value.setText(data+"");
return view;
}
private class ViewHolder {
TextView value;
}
Now I want to update the ListView with as soon as the Thread in the update() method has finished getting the new data. Getting the data can take several seconds, so it's impossible to predict, what activity will be active by that time. If my ListViewActivity is active, I want the ListView to change to the new data immediately.
So how do I update that ListView, from a different class, which is not an Activity, inside another thread? I don't suppose putting the adapter in a static field is a good idea, since that ListViewActivity is probably created and destroyed all the time? But what other options do I have?
Define a callback interface. Make your update method take an instance of this callback as an argument and call back to it when updating has finished.
public interface UpdateCallback {
public void onUpdateFinished();
}
public void update(final Context context, final UpdateCallback callback) {
new Thread(new Runnable() {
#Override
public void run() {
// do lots of complicated stuff
callback.onUpdateFinished();
}
}).start();
}
Then in your Activity you can notify that the adapter data has changed:
Data.update(this, new UpdateCallback() {
public void onUpdateFinished() {
adapter.notifyDatasetChanged();
}
});
extendIt looks like your major problem can be formulated shortly as "How do I even get the Adapter", so I'll try to address that. Let us try to use an old good Java singleton to solve the problem. The idea is to create a global config and pre-create adapters for all views that you need to update:
public class GlobalConfig {
private static GlobalConfig config = null;
private CustomBaseAdapterOne adapter1 = null;
private CustomBaseAdapterTwo adapter2 = null;
public GlobalConfig getAdapterOne() {return adapter1;}
public GlobalConfig getAdapterTwo() {return adapter2;}
public static synchronized GlobalConfig getInstance() {
if (config == null) {
config = new GlobalConfig();
config.adapter1 = new CustomBaseAdapterOne();
config.adapter2 = new CustomBaseAdapterTwo();
}
return config;
}
}
Your ListViewActivity will need to extend DataSetObserver class and register an observer when it starts. You CustomListAdapter would need to register the observer when it starts and it will also need to be able to get initialized with init params (Context in your case) through a function (e.g. setContext), not through a constructor, so in your ListViewActivity you'll need to do something like below:
GlobalConfig cfg = GlobalConfig.getInstance();
CustomerAdapterOne ad = cfg.getAdapterOne();
ad.setContext(this);
ad.registerDataSetObserver(this);
From a separate thread that needs to update the ListView, you'll run:
GlobalConfig cfg = GlobalConfig.getInstance();
try {
cfg.getAdapterOne().notifyDataSetChanged();
}
catch{... }
I think, it's a good idea to have try/catch here because I don't know what will happen if ListView has already died at the time when you need to notify.
To summarize: you'll need to pre-create one adapter for each view that needs to be updated and make it globally available for everyone who needs it.
I'm trying to hide a button inside getView method of an Adapter. Unfortunately, I can't do it.
private class AppListAdapter extends ArrayAdapter<Info> {
public AppListAdapter(Activity activity, List<Info> apps) {
super(activity, android.R.layout.simple_list_item_1, apps);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// if we weren't given a view, inflate one
if (null == convertView) {
convertView = getLayoutInflater()
.inflate(R.layout.activity_apps, null);
}
btnUninstall = (Button) convertView.findViewById(R.id.uninstallButton);
btnUninstall.setOnClickListener(
new View.OnClickListener() {
#Override
public void onClick(View v) {
btnUninstall.setVisibility(View.INVISIBLE);
}
}
);
return convertView;
}
}
Any help shall be appreciated?
Try changing this line
btnUninstall.setVisibility(View.INVISIBLE);
To this
v.setVisibility(View.INVISIBLE);
That's because in the adapter android passes the same view over and over again (recycling), try to set the visibility of the button to visible every time.
I checked the code and it works fine for me.!
Hey quick question though, have you declared your btnUninstall anywhere?
I cannot see it anywhere in the code you have provided, thats all.
Button btnUninstall;
I'm developing an Android game with LibGDX. And I need to find the height of the soft-keyboard the user is using, as I want to display some objects right above the keyboard.
I have read this thread:
how can i get soft keyboard height on android?
But the comment suggests that it doesn't work, and it also seems to be for using with Android SDK. I'm not sure. Does anyone know a way that will definitely work?
If your problem is that your textfields are obscured then I suggest using
void Gdx.input.getTextInput(Input.TextInputListener listener,
java.lang.String title,
java.lang.String text)
instead because that will generate a native modal text input dialog that moves up and down with the keyboard. I have tried to get the height of the keyboard as well but so far I haven't managed.
See answers for this thread as well:
How do libgdx detect keyboard presence
Hopefully someone will find this answer helpful:
There is a workout to detect the exact height of the soft-keyboard which involve the Launcher Activity to send screen dimension to the game when a screen resize event occurs.
First, set a layout listener on the ViewTreeObserver of the rootView of your LauncherActivity:
public class AndroidLauncher extends AndroidApplication {
//...
public void setListenerToRootView() {
final View activityRootView = getWindow().getDecorView().findViewById(android.R.id.content);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(keyboardLayoutListener);
}
private ViewTreeObserver.OnGlobalLayoutListener keyboardLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
Rect visibleDisplayFrame = new Rect();
getWindow().getDecorView().getWindowVisibleDisplayFrame(visibleDisplayFrame);
game.screenResize(visibleDisplayFrame.width(), visibleDisplayFrame.height());
}
};
//...
}
If you try to get the height of the root view, it will not work as most of the games are fullscreen.
Don't forget to add and remove the listener on appropriate occurrences:
#Override
protected void onCreate (Bundle savedInstanceState) {
//...
setListenerToRootView();
}
#Override
protected void onDestroy () {
super.onDestroy();
removeListenerToRootView();
}
public void removeListenerToRootView() {
final View activityRootView = getWindow().getDecorView().findViewById(android.R.id.content);
activityRootView.getViewTreeObserver().removeOnGlobalLayoutListener(keyboardLayoutListener);
}
Next, declare the screenResize method inside the Game Class which will receive the dimensions and send it to the current screen:
public class YourGame extends Game {
//...
public ScreenBase currentScreen;
//...
public void screenResize(float width, float height) {
if(currentScreen != null)
currentScreen.onScreenResize(width, height);
}
//...
}
Every screen that involves a change must implement the onScreenResize method. Introduce an Abstract Base Class of screen that has an abstract method onScreenResize. The currentScreen variable must be set in the constructor:
public abstract class ScreenBase implements Screen {
//...
public ScreenBase(YourGame game) {
//...
this.game = game;
this.game.currentScreen = this;
//....
}
public abstract void onScreenResize(float width, float height);
Implement these in whichever screen you want:
public class LoginScreen extends ScreenBase {
//...
#Override
public void onScreenResize(final float width, final float height) {
if(Gdx.graphics.getHeight() > height) {
Gdx.app.log("LoginScreen", "Height of keyboard: " + (Gdx.graphics.getHeight() - height));
}
}
}
How to make checkbox/combobox readonly in javaFX but not disabled.
I tried consuming onAction event but it didn't work.
checkBox.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
event.consume();
}
});
Consuming all events like in code below works but I don't think it's a good solution:
checkBox.addEventFilter(KeyEvent.ANY, new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent event) {
event.consume();
}
});
checkBox.addEventFilter(MouseEvent.ANY, new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEventevent) {
event.consume();
}
});
You can set the check box to disabled but set the the look of it using CSS. If you are using the default style you can make the check box look 'normal' by setting full opacity.
checkbox.setStyle("-fx-opacity: 1");
It is probably a similar deal with the combo box.
You can override method CheckBox#arm() with an empty one:
CheckBox cb = new CheckBox("hi") {
#Override
public void arm() {
// intentionally do nothing
}
};
If you do not want to overwrite the CheckBok class, you can use the selectedProperty.
CheckBox cb = new CheckBox("hi");
cb.selectedProperty().addListener(new NCL());
class NCL implements ChangeListener<Boolean> {
#Override
public void changed(ObservableValue<? extends Boolean> ov, Boolean old_val, Boolean new_val) {
cb.setSelected(false);
}
}
I have a question on the Event Handling in JavaFX. As per the tutorial (and other examples that I came across), event handling is carried the following way in JavaFX:
Button addBtn = new Button("Add");
addBtn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
System.out.println("Add Clicked");
}
});
But, I am wondering, if I can "handle" the button click the following way:
Button addBtn = new Button("Add");
addBtn.setOnAction(new addButtonClicked());
where addButtonClicked() is my own Class (with it's own set of methods and functionality) that I have defined and written to handle the actions for the button click.
Is there a way to attach my own event handler classes for buttons in JavaFX?
The EventHandler is an interface class.
So, it should be "implements" not "extends"
private static class AddButtonClicked implements EventHandler<ActionEvent> {
#Override
public void handle(ActionEvent event) {
System.out.println("My Very Own Private Button Handler");
}
}
Sure.
private static class AddButtonClicked extends EventHandler<ActionEvent> {
#Override
public void handle(ActionEvent event) {
System.out.println("My Very Own Private Button Handler");
}
}