I have a curious problem with getting reference on TextView, SeekBar and other widgets. My AlertDialog looks like this:
public class LineDialog extends AlertDialog {
private static SeekBar seekBar1, seekBar2, seekBar3;
private static TextView textView1, textview2, textView3;
protected LineDialog(final Context context, final DrawView drawView) {
super(context);
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View dialogLayout = inflater.inflate(R.layout.line_dialog, null);
setView(dialogLayout);
setTitle("Line properties");
textView1 = (TextView) findViewById(R.id.textView1); // TODO Code crash here :(
setButton("Ok", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
seekBar1 = (SeekBar) findViewById(R.id.seek1);
// some other code...
}
});
}
When I want get reference in Line where is
textView1 = (TextView) findViewById(R.id.textView1);
Logcat send me an Error
requestFeature() must be called before adding content
But when I get reference in onClick() method in LineDiealog(AlertDialog) everything works fine. Unfortunately this is too late, because I need this reference before LineDialog.show() is called...
You almost had it there in your original code. You saved the View returned by LayoutInflater, so that's the one you should use when calling findViewById() so it must be dialogLayout.findViewById(...). I was having the same issue myself and works like charm now.
Here is an example of the custom AlertDialogbox and How to implement a custom AlertDialog View
you can see how to add the view to the alertdialogbox.
You must either reference your textView by LinearLayout or by android:id in the xml file.
LinearLayout example:
LinearLayout mainLinear = new LinearLayout(this);
mainLinear.addView(textBox);
the add text to the box:
textBox.addText("This is the text to add to the text box");
xml reference (you must create the text box in xml first!!!!):
TextView text1=(TextView) findViewById(R.id.NAME);
text1.setText("Hello please pick an option below");
The NAME portion must be replaced with the android:id name in the .xml file
Related
Is it possible to find the added TextView to update it with other options.
I am adding by this code new TextView with a Button. Now, I want also set a onClickListerner for the dynamically added TextViews. For this I have to find them with findViewById method. But they aren't createt yet.
Can I make this in a other way and if yes, How?
Button hinzufügenButton = (Button) findViewById(R.id.hinzufügen_Button);
hinzufügenButton.setOnClickListener(new Button.OnClickListener() {
public void onClick (View view){
EditText tischName = (EditText) findViewById(R.id.tisch_name_EditText);
TextView tisch = new TextView(getApplicationContext());
tisch.setText(tischName.getText());
tisch.setAllCaps(true);
tisch.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
tisch.setBackgroundColor(Color.parseColor("#9FA8DA"));
tisch.setTextSize(25);
tisch.setId(id);
id++;
LinearLayout tischeAnzeigen = (LinearLayout) findViewById(R.id.tische_LinearLayout);
tischeAnzeigen.addView(tisch);
}
});
Just add the onClickListener as you create your dynamic views
Example:
...
tisch.setId(id);
tisch.setOnClickListener(yourListener);
...
You can use setId to add an id. But you probably don't need to. If you're creating a view dynamically, you have a reference to it when you create it. Just set it on that reference. No need to find it.
I am using revision 26.0.1 of the Android Support Library to set custom fonts in my app. In my app's theme, I added:
<item name="android:fontFamily">#font/my_font</item>
It worked like a charm, converting the text in my whole app to my custom font. EXCEPT for my dialogs - specifically their titles, messages, and also their NumberPickers. In those places, fonts were not updated. (Radio buttons and checkboxes worked; so did the yes/no buttons)
Is there something I'm forgetting to add to my themes or styles? Or is this simply not supported yet by the support library?
A little more detail: I am using AppCompatDialogFragment to implement all my dialogs. In their onCreateDialog() methods, I create a dialog using AlertDialog.Builder then return it.
Thanks for the help!
Thank you everybody who answered, but unfortunately none of those solutions worked for me. I hope they will work for someone else.
I've concluded that this is a bug in the support library, and hopefully Google will fix. In the meantime, I developed this hacky workaround:
public static void applyCustomFontToDialog(Context context, Dialog dialog) {
Typeface font = ResourcesCompat.getFont(context, R.font.my_font);
if (font != null) {
TextView titleView = dialog.findViewById(android.support.v7.appcompat.R.id.alertTitle);
TextView messageView = dialog.findViewById(android.R.id.message);
if (titleView != null) titleView.setTypeface(font, Typeface.BOLD);
if (messageView != null) messageView.setTypeface(font);
}
}
This works by scanning the dialog's view tree for the title and message views by the IDs that the support library gives them. If the support library were to change these IDs, this would no longer work (which is why it's hacky). Hopefully Google fixes this issue and I won't need to do this anymore.
I've found a way that only requires a one-line change to Java code every time you create an AlertDialog.
Step 1
Create a custom, reusable layout containing a TextView with the correct font set. Call it alert_dialog.xml:
<?xml version="1.0" encoding="utf-8"?>
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
style="#style/SomeStyleWithDesiredFont"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="#dimen/spacing_2x" />
Step 2
Create a reusable helper function somewhere that will inflate this layout and set the text to your desired string
public static TextView createMessageView(String message, Context context) {
TextView messageView = (TextView) LayoutInflater.from(context).inflate(R.layout.alert_dialog, null, false);
messageView.setText(message);
return messageView;
}
Step 3
In every AlertDialog.Builder chain in your code, replace this line:
.setMessage(messageString)
with this line:
.setView(createMessageView(messageString, context))
(Note that the same approach should work for the title TextView. You can apply a custom view for the title by calling setCustomTitle() in your builder)
You should use a ContextThemeWrapper when creating the dialog builder. Like this
ContextThemeWrapper wrappedContext = new ContextThemeWrapper(context, R.style.mystyle);
AlertDialog.Builder builder = new AlertDialog.Builder(wrappedContext);
If you are supporting only SDK 11 and above, you may want to use
ContextThemeWrapper wrappedContext = new ContextThemeWrapper(context, R.style.mystyle);
AlertDialog.Builder builder = new AlertDialog.Builder(wrappedContext, R.style.mystyle);
Perhaps not the case here, I had a similar issue and found that fontFamily would not be impimented using the AsyncLayoutInflater. This is also the case if the AlertDialog is nested inside the AsyncLayoutInflater. I had to convert to the conventional layout inflator in order for the custom font to show. For example,
This did not show fontFamily called from TextView XML.
AsyncLayoutInflater inflater =new AsyncLayoutInflater(activity);
inflater.inflate(R.layout.dialog, null, new AsyncLayoutInflater.OnInflateFinishedListener() {
#Override
public void onInflateFinished(#NonNull View view, int resid, ViewGroup parent) {
final TextView tv = view.findViewById(R.id.textview);
tv.setText("Text with custom fontFamily called in XML, but won't work");
}
});
This did show fontFamily called from TextView XML.
final ViewGroup nullParent = null;
final View view = activity.getLayoutInflater().inflate(R.layout.dialog, nullParent);
final TextView tv= view.findViewById(R.id.textview);
tv.setText("Text with custom fontFamily called in XML, and will work");
you can inflate a custom layout in your dialog like this:
final android.support.v7.app.AlertDialog.Builder alertDialogBuilder = new android.support.v7.app.AlertDialog.Builder(context,
R.style.LimitAlertDialogStyle);
LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View alertLayout = layoutInflater.inflate(R.layout.date_layout, null);
TextView tv= (TextView) alertLayout.findViewById(R.id.tv);
Typeface fc=Typeface.createFromAsset(getAssets(),"fonts/FONT");
tv.setTypeface(fc);
You can use custom Alert Dialog and set the font using Typeface. Have a look at below code snippet.
AlertDialog dg = new AlertDialog.Builder(this).setMessage("Your Message").show();
TextView tv = (TextView) dg.findViewById(android.R.id.message); // Your TextView of custom Alert Dialog
Typeface fc=Typeface.createFromAsset(getAssets(),"fonts/FONT"); // This is your font file name.
tv.setTypeface(fc);
I have this FlowLayout where I have a set of TextView's which I build programatically. After getting the wanted names, I create a TextView for each name inside the layout.
What I want to do, if I click on the TextView, I want to move it into another layout. I manage to do that but I also want to move it back. I could also do that until I program it to, but I can't program it to be like a infinite loop.
This is a piece of code which will make you understand better what I'm talking about hopefully.
TextView tv = new TextView(new ContextThemeWrapper(getActivity(), R.style.FlowLayoutTextView));
tv.setText("Test");
tv.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
TextView tvSelected = new TextView(new ContextThemeWrapper(getActivity(), R.style.FlowLayoutTextView));
tvSelected.setText(tv.getText().toString());
tvSelected.setLayoutParams(params);
tv.setVisibility(View.GONE);
filteredLayout.addView(tvSelected);
}
});
unfilteredLayout.addView(tv);
Is it possible to make it work? Thanks.
LE: As you can see in the onClickListener event of the TextView, I create the other TextView I add in the other layout, to move it back I could also add an onClickListener event to this TextView but this is not the solution.
Try following:
boolean isInFilterLayout = false; //Class variable
TextView tv = new TextView(new ContextThemeWrapper(getActivity(), R.style.FlowLayoutTextView));
tv.setText("Test");
tv.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(isInFilterLayout){
filteredLayout.remove(tv);
unfilteredLayout.addView(tv);
isInFilterLayout = false;
}else{
unfilteredLayout.remove(tv);
filteredLayout.addView(tv);
isInFilterLayout = true;
}
}
});
unfilteredLayout.addView(tv);
I want to implement a feature that allows user to change the textSize of a textView in another view inside the app,
So I have a button with its "onClick" property set to:
Class mainActivity
public void increaseFont(View view)
{
MainViewPager.changeTextViewTextSize(mTextSize);
}
Class MainViewPager
static public void changeTextViewTextSize(int aTextSize)
{
View detailView = (View) LayoutInflater.from(mContext).inflate(R.layout.details, null);
TextView description = (TextView) detailView.findViewById(R.id.story_description);
description.setTextSize(aTextSize);
}
QUESTIONS is the textSize can't be changed when clicking the button. So how to?
The text size can changed at run time of course. You issue is related to the method changeTextViewTextSize. Using the inflater you are creating a new instance of R.layout.details, and through it, you are looking for the TextView you want to change the text size. But that layout is not at screen. It is not what you are seeing.
In my activity there are 3 buttons. By clicking on the first button, I want a dialog to appear with a graph (in the layout itself it works fine).
btn1 = (Button)findViewById(R.id.btn1);
btn1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
dialog = new Dialog(ChartsDuration.this);
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(R.layout.dialog_charts1);
// code to show a graph. Here I have a function that calls drawChartAll(),
// but since the layout is declared outside the dialog it cannot render it to the
// linearlayout, and my graph1 linearlayout will be empty.
dialog.show();
}
});
Tha graph uses data that are queried in functions outside like
public void drawChartAll()
{
//blablabla and this is how I define the layout and render the graph to it:
LinearLayout layout = (LinearLayout) findViewById(R.id.graph1);
mChartView = ChartFactory.getBarChartView(ChartsDuration.this, buildBarDataset(titles, values),renderer,Type.DEFAULT);
mChartView.setBackgroundColor(renderer.getBackgroundColor());
layout.addView(mChartView);
}
So without the dialog, I can easily show the graph in the graph1 LinearLayout e.g below the buttons, because they are "on the same levels", but I want to show the graph in a dialog opened by clicking on a button. Because if I were in a dialog I would do this: LinearLayout layout = (LinearLayout)dialog.findViewById(R.id.graph1); But now I cannot do this, since I am outside the dialog.
How do I reach this layout?
Edit:
user113215 I did this:
in the activity:
LayoutInflater inflater = LayoutInflater.from(ChartsDuration.this);
customDialog = (ViewGroup) inflater.inflate(R.layout.dialog_charts1, null);
btn1 = (Button)findViewById(R.id.btn1);
btn1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
dialog.setContentView(customDialog);
//queries
dialog.show();
}
});
and in drawChartAll:
public void drawChartAll()
{
//code
LinearLayout layout = (LinearLayout) customDialog.findViewById(R.id.graph1);
}
Is this what you mean? This throws me a nullpointer exception to dialog.setContentView(customDialog); line.
If I understand the problem correctly, you're having trouble manipulating things on the layout that's going into the dialog. Instead of calling setContentView(int), inflate the layout yourself and then use setContentView(View).
LayoutInflater inflater = LayoutInflater.from(this);
ViewGroup customDialog = (ViewGroup) inflater.inflate(R.layout.dialog_charts1, null);
// Do chart things here
// Prefix all calls to findViewById with "customDialog."
LinearLayout layout = (LinearLayout) customDialog.findViewById(R.id.graph1);
mChartView = ChartFactory.getBarChartView(ChartsDuration.this, buildBarDataset(titles, values),renderer,Type.DEFAULT);
mChartView.setBackgroundColor(renderer.getBackgroundColor());
layout.addView(mChartView);
// Put the manipulated layout into the dialog
dialog.setContentView(customDialog);
You can use this same trick to take advantage of the AlertDialog.Builder class while still filling the dialog with a custom layout.
Make the dialogvariable a field in your Activity class. You can reach it from anywhere. You can still use dialog.findviewbyid throughout you Activity. Just make sure setcontentView has been called before you call findviewbyid
Edit: I hope when you wrote since I am outside the dialog. you meant you could not access the variable