Am posting this in hopes to help someone else; but, if there is an easier way to do the same, I hope someone can share their steps. If I use the method 'setDisplayedValues' to pass an array of values to display in the NumberPicker, the underlying method forces the use of a Text Keyboard Layout, instead of the Number Layout, which isn't what I want.
I found a way to set the InputType for my NumberPicker. This is done in my extended class:
class public class NumberPickerDialogFragment extends DialogFragment:
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
// We are getting the parameters passed in to figure out the range of the Number Picker
NumPickerValues = getArguments().getStringArray("NumPickerRange");
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
// Get the layout inflater
LayoutInflater inflater = getActivity().getLayoutInflater();
View dlgNumPicker = inflater.inflate(R.layout.dialog_num_picker, null);
NumberPicker np = (NumberPicker) dlgNumPicker.findViewById(R.id.npNumberPicker);
// Always remember that NumberPicker methods need an index position, rather than the value in that array position
np.setMinValue(0);
np.setMaxValue(NumPickerValues.length-1);
np.setDisplayedValues(NumPickerValues);
np.setValue(getArguments().getInt("InitialValue"));
np.setWrapSelectorWheel(false);
np.setOnValueChangedListener(this);
// Since the underlying code for the NumberPicker sets the keyboard layout for text, due to the use of 'setDisplayedValues',
// we need to set it back to a number keyboard layout
((EditText)np.getChildAt(0)).setRawInputType(InputType.TYPE_CLASS_NUMBER);
// Inflate and set the layout for the dialog
// Pass null as the parent view because its going in the dialog layout
return builder.setView(dlgNumPicker)
.setTitle(getArguments().getInt("NumPickerTitle"))
.setPositiveButton(getArguments().getInt("SaveButtonTitle"), new ButtonCLickListener())
.setNegativeButton(R.string.cancel, new ButtonCLickListener())
.create();
}
On the section of code above, the line that sets the InputType is
((EditText)np.getChildAt(0)).setRawInputType(InputType.TYPE_CLASS_NUMBER);
I didn't find anything on the web that does this. It seems like a clean way of doing it; but, am not sure if there is any performance issues by doing it this way. If there is, let us know.
Related
I am trying to make a dialog that consists of a LinearLayout which contains a number of other LinearLayouts that are effectively Buttons that each bring you to a website. Instead of statically making each LinearLayout Button in the layout xml file, I have a JSON feed that has a possibly changing number of buttons to display in the dialog. I found a question that looks similar...
... but I'm not sure how to dynamically add LinearLayouts to a Dialog. The data for each of the LinearLayout buttons gets parsed into an ArrayList of items, each representing a Button in the Dialog.
Normally you should use a RelativeLayout for this:
To notice, where your last created button is and to set the next one to the next position costs not so much performance as creating new layouts. You should try to call addView(); as less as possible, because each time the view must be rendered again.
But if it's necessary to add LinearLayouts, here is a sample code:
LinearLayout linearLayout = new LinearLayout(context);
linearLayout.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
linearLayout.setOrientation(LinearLayout.VERTICAL);
viewGroup.addView(linearLayout);
Use a ListView or RecyclerView and control it with an adapter.
For the dialog you can use a DialogFragment. Override the onCreateDialog method and return an AlertDialog inside. The AlertDialog.Builder has the setView method that you can use to inflate your list or recycler. Then just keep a reference to the adapter in your dialog fragment and use it to load your layout-buttons dynamically.
For example:
public class WebsitePickerDialogFragment extends DialogFragment {
Adapter adapter = new YourRecyclerViewAdapter();
#NonNull
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final RecyclerView contentView = LayoutInflater.from(getContext()).inflate(...
contentView.setAdapter(adapter);
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setView(contentView);
return builder.create();
}
}
If you don't want scrolling behavior, you can still use this pattern with any adapter view, like the https://github.com/frankiesardo/LinearListView lib that uses LinearLayout like a ListView.
Is there any difference between these methods? I'd like to create the dialog first so that I have the reference to it when something is clicked in the view to dismiss it. Obviously that's not possible if I'm setting the view with the builder and the alert is not created yet.
As per AlertDialog.Builder source it makes no difference.
"I'd like to create the dialog first so that I have the reference to
it when something is clicked in the view to dismiss it."
The user can't click to dismiss the dialog until to you show it to them, and that is after you have created an instance. See the lifecycle example below:
View someView = ...;
View someOtherView= ...;
AlertDialog.Builder builder = new AlertDialog.Builder(this);
//sets the view, but doesn't show anything.
builder.setView(someView);
//now we have an instance of AlertDialog, still not shown
AlertDialog dialog = builder.create();
//now we showed it
dialog.show();
//...(wait some time)
//now we changed its view after being shown
dialog.setView(someOtherView);
I'm new to android, so maybe I'm doing something horribly wrong. I want to have a particular Activity that shows details about an instance of a "Creature" class for a game. Name, damage taken, that sort of thing.
I'm having a problem getting the creature data to be properly shown in the GUI objects. Both at initial creation (where it should copy the creature's name into the name field) and when a damage mark is added (where it doesn't update to show the proper image).
Here's my mini-example of what I have:
public class CreatureDetailActivity2 extends Activity
{
Creature creature;
public void addMark(View v)
{
// connected to the button via android:onClick="addMark" in the XML
creature.getTrack().addDamage(DamageType.Normal, 1);
refreshDisplay();
new AlertDialog.Builder(this).setTitle(creature.getName())
.setMessage(creature.getTrack().toString()).show();
}
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_creature_detail);
creature = new Creature("Example");
refreshDisplay();
}
public void refreshDisplay()
{
final View creatureDetailView = this.getLayoutInflater().inflate(
R.layout.activity_creature_detail, null);
final EditText nameField = (EditText) (creatureDetailView
.findViewById(R.id.textbox_creature_name));
nameField.setText(creature.getName());
final ImageView damageBox0 = (ImageView) (creatureDetailView.findViewById(R.id.damageBox0));
damageBox0.setImageResource(R.drawable.__n);
// in the full program this does the same for 0 through 9, but this is a sample
// also, in the full program, this is a dynamic lookup for the correct pic
// but again, this is just a sample version.
}
}
Now the problem is that the app will load up and start, but then none of the widgets will update properly. You can click the button, and it'll show the AlertDialog, and the text of the AlertDialog will change, but the textfield in the activity won't be changed, and the ImageView doesn't change at any point from what it starts as to the one it's supposed to change to.
So I'm very stumped. I can post more about the project's setup if I'm leaving out something important, but I'm not even sure what the problem going on is so I'm not sure what else to include in my question.
final View creatureDetailView = this.getLayoutInflater().inflate(
R.layout.activity_creature_detail, null);
Inflates your Activity's layout into basically nothing, just returning the View it inflated. setContentView is what actually inflates your layout into the Activity's View hierarchy.
Once you inflate your layout you don't need to do it again. Just use findViewById without the reference to a dangling unattached View.
Change your refreshDisplay method to this:
public void refreshDisplay()
{
final EditText nameField = (EditText) findViewById(R.id.textbox_creature_name);
nameField.setText(creature.getName());
final ImageView damageBox0 = (ImageView) findViewById(R.id.damageBox0);
damageBox0.setImageResource(R.drawable.__n);
// in the full program this does the same for 0 through 9, but this is a sample
// also, in the full program, this is a dynamic lookup for the correct pic
// but again, this is just a sample version.
}
Nothing changes because You do it completely wrong.
If You wish to update any view element of current activity You do it like this
View v = findViewById(R.id.element);
v.setText("text");
this is just simple example.
You would need to cast a returned element to correct type like to be able to access all available methods.
What You do wrong is trying to inflate a layout again.
I need to show an AlertDialog with a ListView and a context menu for the ListView items. I prefer to use AlertDialog.Builder and call setItems(), so the Builder creates a ListView inside the AlertDialog with stylized layout for me. For the stylizing it uses internal Android resources, so I cannot reimplement it in my code.
The problem is that I cannot catch a context menu item click event because of default AlertDialog.onMenuItemSelected() implementation, which does not forward such events to the parent:
public boolean onMenuItemSelected(int featureId, MenuItem item) {
return false;
}
I cannot extend AlertDialog.Builder class and force it to create an instance of my own AlertDialog with onMenuItemSelected() overridden because I need to override AlertDialog.Builder.create() for that. But it uses a private P variable, which is not accessible from a derived class:
public AlertDialog create() {
final AlertDialog dialog = new AlertDialog(P.mContext, mTheme, false);
P.apply(dialog.mAlert);
dialog.setCancelable(P.mCancelable);
if (P.mCancelable) {
dialog.setCanceledOnTouchOutside(true);
}
dialog.setOnCancelListener(P.mOnCancelListener);
if (P.mOnKeyListener != null) {
dialog.setOnKeyListener(P.mOnKeyListener);
}
return dialog;
}
Is there a way to force AlertDialog.Builder to construct a custom AlertDialog (with onMenuItemSelected method overridden)?
I still found no solution for the question, but I found some problems, which makes the solution useless. For Android 2.1, built-in ListView items (android.R.layout.select_dialog_item) are displayed as black text on dark grey background, ListView items are not separated from the dialog message (setMessage()), etc.
I finally switched back to my own AlertDialog with custom layout for ListView and its items (AlertDialog.Builer not used). Context menu events can be easily catched this way.
Luksprog, thanks a lot for your comments. But the main idea was to use as many stylized layouts, as possible. AFAIK, no standard layouts (android.R.layout.*) offer the buttons you mentioned. Also, an item could be removed occasionally with the button. With a context menu, at least two click required to remove an item.
My app contains 25 edittexts. I am getting this 25 edittexts with the help of adapter class by giving count=25 and fitting in gridView by gridView.setAdapter(new TextAdapter(this)); in the activity class. So, the edittexts are dynamically generated. But the thing is I am unable to set the initial values in the edittexts. This is because the edittext objects are unavailable to set the values.
Suppose if I don't set any initial values in the edittexts and continue with my app. The same problem repeats while setting the values back in the edittexts which are entered in previous mode after changing the orientation. Because change in orientation creates new activity. Even I tried android:configChanges="orientation|keyboardHidden", but no use while I am setting the values back in the **onConfigurationChanged()**. Because I am setting the setContentView(); in the onConfigurationChanged() as I need the respective view, but still the edittext objects are unavailable to set their values.
Is there any solution to set back the values? If not, I am thinking(Might be completely wrong way, but as a newbie please go easy) to move the onCreate() method content to Application class. So the initial part goes to Application class including the creation of edittexts. and getting that edittext objects in the onCreate() method to set the values. Is it possible? Please suggest. Code snippet would be appreciated.
You will need to modify TextAdapter. Store the initial values in a String array, with the position of the String array element aligned to the position of the EditText in your GridView.
Pseudo-code (untested):
public class TextAdapter extends BaseAdapter {
String [] initial_value = {"Initial Value 1", "Initial Value 2", "Initial Value 3", ..., };
public View getView(int pos, View view, ViewGroup viewGroup) {
if (view == null) {
LayoutInflater inflater = (LayoutInflater) this.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.edit_text_container, null);
}
(EditText) edtTemp = (EditText) view.findViewById(R.id.edit_text_id);
edtTemp.setText(initial_value[pos]);
}
}