I know that Android Presentations can have their own layouts which means I can create UI components like buttons etc. However, does anyone know if it is possible for Presentations to handle touch events?
I have tried adding a button on the Presentation layout and registering a button onClickListener but it seems to not be working. Is there another way?
Here is my code:
In my Presentation class
mHelloToast = (Button) findViewById(R.id.btn_presentation_hello_toast);
mHelloToast.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast toast = Toast.makeText(getContext(), "hello presentation", Toast.LENGTH_SHORT );
toast.show();
}
});
Edit: bump
Doc says:
A presentation is a special kind of dialog whose purpose is to present content on a secondary display. A Presentation is associated with the target Display at creation time and configures its context and resource configuration according to the display's metrics.
So I think Android Presention can handle touche event as Dialog.Here I will show you how Dialog handles touch event.
Step 1
Create your custom layout res/layout/dialog_signin.xml.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<Button
android:id="#+id/btn_presentation_hello_toast"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
Step 2
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
// Get the layout inflater
LayoutInflater inflater = getActivity().getLayoutInflater();
// Get the view which you want to receive touch event
//// Pass null as the parent view because its going in the dialog layout
View rootView = inflater.inflate(R.layout.dialog_signin, null);
Button bt = (Button)rootView.findViewById(R.id.btn_presentation_hello_toast);
// set click or touch listener
bt.setOnClickListener(....);
// set dialog's contents
builder.setView(rootView);
Related
I´m working on two layouts: the main one and another one (a card layout). I included the card layout inside the main layout, with the following code:
<include
android:id="#+id/miPrueba"
layout="#layout/card_product_details"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:elevation="10dp"
android:layout_margin="15dp"/>
This works fine, but I have buttons in my main layout and I need to use them. When I try to find them, using findViewByIdid from my card layout, I use this code:
View view = LayoutInflater.from(getApplication()).inflate(R.layout.card_product_details, null);
Button prueba = (Buttton) view.findViewById(R.id.buttonId);
prueba.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(getApplicationContext(), "Toast por defecto", Toast.LENGTH_SHORT).show();
}
});
What I get is nothing, no error, no null pointer exception, nothing. Simple, it does not respond when I click it.
How I can solve it?
Need more of your code but from what you have given the reason you are having this problem is that the card doesn't have the button buttonId
When you are creating
View view = LayoutInflater.from(getApplication()).inflate(R.layout.card_product_details, null);
I have a need to show a minimally-intrusive non-blocking notification which is not tied to the activity it was shown in (like a Toast) and which is clickable. Anyone have any idea whether or not this is possible? Unfortunately, it appears that Toast notifications (custom or otherwise) are not clickable (i.e. setting an OnClickListener on its views has no effect). All the alternatives that I'm aware of (i.e. AlertDialog, PopupWindow and Crouton) seem to show a notification which is tied to the activity it was shown in (i.e. they won't continue showing when the activity finishes). Any suggestions?
You can use PopupWindow, add an onClickListener and add a handler to auto cancel it after n times (just like the behavior of a toast). Something like this:
public static void showToast(Activity a, String title, String message) {
// inflate your xml layout
LayoutInflater inflater = a.getLayoutInflater();
View layout = inflater.inflate(R.layout.custom_toast,
(ViewGroup) a.findViewById(R.id.toast_layout_root));
// set the custom display
((TextView) layout.findViewById(R.id.title)).setText(title);
((TextView) layout.findViewById(R.id.message)).setText(message);
// initialize your popupWindow and use your custom layout as the view
final PopupWindow pw = new PopupWindow(layout,
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT, true);
// set windowType to TYPE_TOAST (requires API 23 above)
// this will make popupWindow still appear even the activity was closed
pw.setWindowLayoutType(WindowManager.LayoutParams.TYPE_TOAST);
pw.showAtLocation(layout, Gravity.CENTER | Gravity.TOP, 0, 500);
// handle popupWindow click event
layout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// do anything when popupWindow was clicked
pw.dismiss(); // dismiss the window
}
});
// dismiss the popup window after 3sec
new Handler().postDelayed(new Runnable() {
public void run() {
pw.dismiss();
}
}, 3000);
}
xml layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/toast_layout_root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#000"
android:orientation="vertical"
android:elevation="10dp"
android:padding="20dp">
<TextView
android:id="#+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:textColor="#FFF"
android:textStyle="bold"/>
<TextView
android:id="#+id/message"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:textColor="#FFF"/>
</LinearLayout>
You are right, a Toast object has no way to be interacted with, but there are many libraries out there that will give you the same look and feel as a toast, but with some interactivity. The one I use is https://github.com/JohnPersano/SuperToasts
I think what you need is in fact a PopupWindowwhich can be seen here "http://developer.android.com/reference/android/widget/PopupWindow.html".
Toasts have a very specific task, which is to inform the user, without any input from them. So instead of trying to extend the purpose of the Toast, use the PopupWindow which can be interacted with by the user.
A 'Dialog' type of activity will probably be your best bet.
In manifest:
<activity android:name=".ToastLikeActivity"
android:theme="#android:style/Theme.Dialog"
android:label="#string/label"
></activity>
And timeout the activity within the onCreate():
class ToastLikeActivity extends Activity {
#Override
public void onCreate(Bundle state)
// auto-kill activity after X seconds <-------------------------
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
ToastLikeActivity.this.finish(); // kill after X seconds
}
}
}, VisibleTimeSecs*1000);
}
To display the dialog start it as with any other activity:
Intent i = new Intent(this, ToastLikeActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(i);
And it will show up and automatically go away after X seconds.
Such a popup will not be tied to the caller activity. In fact - it will not even require a caller activity. You
can activate it (bad idea, but possible) even from a service.
You can implement basically any kind of sensitive (i.e. accepting user's clicks) interface you want to
the ToastLikeActivity. Especially: you can make its exteriors transparent, giving it a dialog-likke looks.
I have a dropdown spinner which is showed when click on a button looks like this:
<Button
android:id="#+id/btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<Spinner
android:id="#+id/spinMenu"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:spinnerMode="dropdown"
android:visibility="invisible" />
<ListView
android:id="#+id/lvWall"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
Here is snippet showing dropdown popup:
findViewById(R.id.btn).setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
spinMenu.performClick();
}
});
My spinner can show dropdown popup correctly. The problem is my layout has a listview which getting data from web service in background. When data is loading completely, all list items will be showed or refreshed, and the spinner's dropdown popup is dismiss (I even don't touch anything on screen). I think the problem is window has changed focus on other view. So how can I prevent it?
Update:
Here is my list after load data from background, it's very simple:
List<Feed> data = result;
FeedAdapter adapter = new FeedAdapter (this, data);
ListView lvWall = (ListView)findViewById(R.id.lvWall);
lvWall.setAdapter(adapter);
And data for spinner:
List<String> list = getMenus();
ArrayAdapter<String> dataAdapter = new ArrayAdapter<String>(this,
android.R.layout.simple_spinner_item, list);
dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinMenu.setAdapter(dataAdapter);
If I understand correctly, you have a Spinner view which you set as invisible with the only purpose of showing the popup menu, but not the Spinner view itself. In that case, the problem is probably related to this snippet in Spinner.java, more precisely in DropdownPopup.show():
public void show(int textDirection, int textAlignment) {
...
super.show();
...
// Make sure we hide if our anchor goes away.
// TODO: This might be appropriate to push all the way down to PopupWindow,
// but it may have other side effects to investigate first. (Text editing handles, etc.)
final ViewTreeObserver vto = getViewTreeObserver();
if (vto != null) {
final OnGlobalLayoutListener layoutListener = new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
if (!Spinner.this.isVisibleToUser()) {
dismiss();
} else {
computeContentWidth();
...
What does this mean? Basically that the Spinner is set up with a ViewTreeObserver to be notified whenever a layout pass changes the views in the screen. And if the Spinner is not visible after that happens, the popup is dismissed. Loading the ListView evidently causes a change in the view hierarchy, and it's being fired when the data arrives from the server.
For general usage this is completely logical: if the Spinner is hidden, or it goes off screen, or something like that, it would be reasonable to make the popup go away. However, it's interferring with what you're attempting to do. It would be nice if you could somehow override isVisibleToUser(), but unfortunately it's marked as #hide, so that's not possible.
Might I suggest a workaround, like setting the Spinner visible but really small? Like, with a height of 1px? I believe that should be enough to fool this method.
Another option, and probably a more sensible one, would be to forgo the Spinner altogether and use a PopupMenu instead. You can anchor it to the Button, load it dynamically, and show it when the button is pressed. The visual effect should be the same.
If you think the problem is due to the change of focus . You can set it with multiple ways.
first create a focuschangeListener and onfocuschange do whatever you like
yourView.setOnFocusChangeListener(testListener);
#Override
public void onFocusChange(View arg0,
boolean isFocused)
{
if(isFocused)
{
//do your work here
}
else
{
}
}
And second way to prevent view from focus..
<!-- Dummy item to prevent AutoCompleteTextView from receiving focus -->
<LinearLayout
android:focusable="true" android:focusableInTouchMode="true"
android:layout_width="0px" android:layout_height="0px"/>
<!-- :nextFocusUp and :nextFocusLeft have been set to the id of this component
to prevent the dummy from receiving focus again -->
<AutoCompleteTextView android:id="#+id/autotext"
android:layout_width="fill_parent" android:layout_height="wrap_content"
android:nextFocusUp="#id/autotext" android:nextFocusLeft="#id/autotext"/>
What I am trying to do is to create a custom dialog that overrides an AlertDialog.
What it is supposed to do is get some text (at least 2 strings) and then for each of those strings it is supposed to be able to get more information, but I want to do this in custom dialogs.
So what is supposed to happen is a user can enter 2 people in an activity screen, and then for the first person, you get a custom dialog and that person can enter three words, and then it jumps to the next custom dialog (exact same layout I am inflating) and the second person can enter some words.
This is my xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/LinLay_Enter_Words"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:id="#+id/TextView_AddPlayerWord_Instruction"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="#dimen/help_text_size"
android:textStyle="bold"></TextView>
<EditText
android:id="#+id/EditText_Word1"
android:layout_height="wrap_content"
android:maxLength="20"
android:layout_width="match_parent"
android:maxLines="1"></EditText>
<EditText
android:id="#+id/EditText_Word2"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:maxLines="1"></EditText>
<EditText
android:id="#+id/EditText_Word3"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:maxLines="1"></EditText>
</LinearLayout>
And this is part of the code:
protected Dialog onCreateDialog(int id) {
switch (id) {
case NOUN_INPUT_DIALOG_ID:
Dialog returnedDialog = initWordDialog();
return(returnedDialog);
}
return null;
}
It calls initWordDialog():
private Dialog initWordDialog() {
LayoutInflater inflater = LayoutInflater.from(this); //(LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
final View dialogLayout = inflater.inflate(R.layout.word_entry_dialog, null);
AlertDialog.Builder builder = new AlertDialog.Builder(this);
...
TextView v1 = (TextView) dialogLayout.findViewById(R.id.TextView_AddPlayerWord_Instruction);
...
v1.setText("SomeText");
builder.setView(dialogLayout);
builder.setTitle(R.string.enter_word_title);
builder.setPositiveButton("Next", onNextSubmit);
AlertDialog wordBuilderDialog = builder.create();
return wordBuilderDialog;
}
I think what I am trying to find has been discussed to some degree here:
Value of EditText in Custom Dialog
Android - Custom Dialog - Can't get text from EditText
How to add two edit text fields in an alert dialog
The problem, I believe, lies here, where all of the examples everyone has their onClick in the same function as their onCreate. My stuff was a bit more complicated and I wanted to separate out the functions; however, as a result, I am now unable to access any of the EditText variables.
Here is my onClick implementation:
private DialogInterface.OnClickListener onNextSubmit = new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
if (setPlayerWords()) {
...
}
};
The part that matters is I don't even get to the part where I'm accessing the edittexts until setPlayerWords is called, and this is where it is failing:
public boolean setPlayerWords() {
PMGamePlay pmObj = (PMGamePlay) getApplicationContext();
String[] playerWords = new String[pmObj.numberOfWordsPlayersGetToInput()];
//LayoutInflater inflater = LayoutInflater.from(this);
//View dialogLayout2 = inflater.inflate(R.layout.word_entry_dialog, null);
//setContentView(R.layout.word_entry_dialog);
final LinearLayout myLayout = (LinearLayout) findViewById(R.id.LinLay_Enter_Words);
final EditText w0 = (EditText) myLayout.findViewById(R.id.EditText_Word1);
final EditText w1 = (EditText) myLayout.findViewById(R.id.EditText_Word2);
final EditText w2 = (EditText) myLayout.findViewById(R.id.EditText_Word3);
String test = w0.getText().toString();
playerWords[0] = w0.getText().toString();
playerWords[1] = w1.getText().toString();
playerWords[2] = w2.getText().toString();
...
return true;
}
I initially tried re-inflating, but that seemed to reset and while the edittexts would not be null, they were reset to have "" in their values.
Then I tried to setContentView on my xml file, but that still gave me a null value.
Now, I just try and simply access the linearlayout, and that also returns a null value. If I just try to access the edittexts by their id directly without first going through its parent linearlayout, it also returns a null value.
At this point, I'm not sure what to do other than to cram everything that I have in these separate functions into the same single onclick, but I really don't want to do that. Is there nothing else I can do to access these edittexts?
Any help would be greatly appreciated!
Have you tried using the long version of inflate inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot) ? I know that if you don't use this method there can be some issues with it grabbing layout characteristics, so might be causing the issue. For the viewgroup you should pick the parrent view for the alert and usually want attachToRoof = false;
So, my current issue is that I can't find an elegant way to update a dialog box when a button is pressed. I can achieve functionally the same result by dismiss() and show(), but that is ugly.
Lets say this dialog has 3 buttons, for selling widgets that the player has. Sell All, Sell 10, and Sell X (amount entered with a EditText). I'd like for the dialog to persist if the player pushes Sell 10, but also to update it's textviews with the new count of widgets.
Pertinent part of the XML layout of the custom dialog:
<LinearLayout android:id="#+id/linearLayout3" android:layout_height="wrap_content" android:layout_width="match_parent">
<TextView android:id="#+id/sell10Text" android:layout_width="wrap_content" android:text="TextView" android:layout_height="wrap_content" android:layout_weight="2"></TextView>
<Button android:text="Sell 10" android:enabled="false" android:layout_width="wrap_content" android:id="#+id/sell10Button" android:layout_height="wrap_content" android:layout_weight="1"></Button>
</LinearLayout>
Pertinent part of the dialog creation:
final Dialog alert = new Dialog(this);
alert.setTitle("Sell how many "+(masterRes.get(currentResIndex).getName())+"?");
alert.setContentView(R.layout.selldialog);
TextView tvsellAll = (TextView) alert.findViewById(R.id.sellAllText);
TextView tvsell10 = (TextView) alert.findViewById(R.id.sell10Text);
//etc etc more handles, including buttons
tvsellAll.setText("Sell All ("+String.valueOf(masterRes.get(currentResIndex).getHeld())+") - $"+String.valueOf(calcCost(masterRes.get(currentResIndex).getHeld())));
tvsell10.setText("Sell 10 - $"+String.valueOf(calcCost(10)));
// etc etc more setTexts
btnsell10.setOnClickListener( new OnClickListener() {
public void onClick(View v) {
if (v.isEnabled()) {
int y=masterRes.get(currentResIndex).getHeld();
masterRes.get(currentResIndex).setHeld(y-10);
held -= 10;
money += (calcCost(10));
updateScreen();
alert.tvsellAll.setText("Sell All ("+String.valueOf(masterRes.get(currentResIndex).getHeld())+") - $"+String.valueOf(calcCost(masterRes.get(currentResIndex).getHeld())));
alert.tvsell10.setText("Sell 10 - $"+String.valueOf(calcCost(10)));
alert.tvsellAmt.setText("Sell Amount (0-"+String.valueOf(masterRes.get(currentResIndex).getHeld())+")");
}
}
});
// etc etc other button handlers, alert.show() at the end
Now obviously the setTexts within the button can't resolve, as they can't see the alert I created, they just see OnClickListener.
I tried handling this like I did with my main activity's updater updateScreen(), which is a Runnable, that is a long list of setTexts and/or invalidates, and is runOnUiThread(updateScreen). Works great for the base activity.
I did some copypasta and tried to make a updateSellScreen(), get it to hook into the custom dialog's textviews, but it can't resolve the alert class... I'm kind of lost now.
Is this even possible without trashing everything and just creating a custom view (which I am very averse to trying to tackle this fresh into Android programming...)
Declare your TextViews as final. You'll still be able to set their texts, it just means you won't be able to reassign the variable references. Don't do alert.tv as the TextView is not an instance variable of your dialog, but rather of the method with which you are creating your dialog. This is the easy way. You could also declare your TextViews as instance variables of your Activity and then update them through a handler.
alert.setTitle("Sell how many "+(masterRes.get(currentResIndex).getName())+"?");
alert.setContentView(R.layout.selldialog);
final TextView tvsellAll = (TextView) alert.findViewById(R.id.sellAllText);
final TextView tvsell10 = (TextView) alert.findViewById(R.id.sell10Text);
//etc etc more handles, including buttons
tvsellAll.setText("Sell All ("+String.valueOf(masterRes.get(currentResIndex).getHeld())+") - $"+String.valueOf(calcCost(masterRes.get(currentResIndex).getHeld())));
tvsell10.setText("Sell 10 - $"+String.valueOf(calcCost(10)));
// etc etc more setTexts
btnsell10.setOnClickListener( new OnClickListener() {
public void onClick(View v) {
if (v.isEnabled()) {
int y=masterRes.get(currentResIndex).getHeld();
masterRes.get(currentResIndex).setHeld(y-10);
held -= 10;
money += (calcCost(10));
updateScreen();
tvsellAll.setText("Sell All ("+String.valueOf(masterRes.get(currentResIndex).getHeld())+") - $"+String.valueOf(calcCost(masterRes.get(currentResIndex).getHeld())));
tvsell10.setText("Sell 10 - $"+String.valueOf(calcCost(10)));
tvsellAmt.setText("Sell Amount (0-"+String.valueOf(masterRes.get(currentResIndex).getHeld())+")");
}
}
});
In activity where you creates your dialog, you can declare private variables of dialog, textviews, etc, then they will be accessible anywhere in activity.
dialogA = new Dialog(myActivity.this, android.R.style.Theme_Dialog);
dialogA.setContentView(R.layout.myDialog);
// ...
tv1 = (TextView) dialogA.findViewById(R.id.textView1);
Button b1 = (Button) dialogA.findViewById(R.id.button1);
b1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String s1 = tv1.getText().toString();
Toast.makeText(myActivity.this, s1, Toast.LENGTH_SHORT).show();
dialogA.cancel();
}
});
dialogA.show();