How to use same layout for different actions in android? - android

I am designing an app which contains around 25 questions.
How to keep changing the questions when i click the next button.
So here the layout remains the same except the question (i.e. the TextView may change according to different questions but other elements like Buttons, background will not change).So creating many layout for different questions is time consuming.
So how can I use the same layout for these many questions.Should I create these many layouts and classes for asking each question??

You should store your questions in a database, or in a static final String[] if there aren't many of them.
Multiple classes are not required here, because you only change the question text, i.e. questionView.setText(newQuestion);.
Then you need 2 buttons - yes and no, which have an OnClickListener set to them, which in return sets the questionView's text with the newQuestion.

Create a class which will extend Fragment. Use your standard layout inside onCreateView.
Create a method inside this class like this:
public static FragmentName newInstance(int question)
{
FragmentName fragment = new FragmentName();
Bundle args = new Bundle();
args.putInt("QUESTION_ID", question);
fragment.setArguments(args);
return fragment;
}
Now inside your fragment's onCreateView method add some code to check the question number and edit the layout as needed
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
/* ... Code to inflate your layout ... */
Bundle arguments = getArguments();
int question = arguments.getInt("QUESTION_ID", 0);
switch(question)
{
/* Add your code in here to modify the layout */
}
/*... ....*/
}
Now just use a fragment manager from your activity to handle the transitions, using FragmentName.newInstance(question_number) to instantiate the single fragments.
This is of course if just programmatically editing the Views from inside the Activity is not enough.

Create different classes but use the same layout for every class. and show/hide required textviews in each class.

Suppose you have parent layout which contain item(Parent view of question just like view container) and resolve it after that infalte your question layout by using this code. and replace the just values on the OnClickListener of yes button.
RelativeLayout item = (RelativeLayout)findViewById(R.id.item);
View child = getLayoutInflater().inflate(R.layout.child, null);
// Access chile view by child.getElementById(id)
item.addView(child);

When you click yes or no change the textview content accrodingly;
yes_button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view) {
tv_question.setText("This is a new question");.
}
});

Related

How to prevent editText from auto filling text when fragment is restored from saved instance?

I have an activity which holds and shows multiple fragments.
When i re-enter the fragment it auto fills text in all the editTexts. The same text for all fields as well.
Example:
Open fragment and fill in text in the two editTexts:
CustomEditText1: [______]
CustomEditText2: [_acb__]
CustomEditText3: [_qwe__]
Click back button and re-enter the fragment
CustomEditText1: [_qwe__]
CustomEditText2: [_qwe__]
CustomEditText3: [_qwe__]
This is my overwritten methods in the fragment:
public AddBookingFragment() {
// Required empty public constructor
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
tabsActivity = (TabsActivity) getActivity();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_add_booking, container, false);
lastNameEditText = (NASEditText) view.findViewById(R.id.nas_add_booking_last_name);
pnrEditText = (NASEditText) view.findViewById(R.id.nas_add_booking_pnr);
addButton = (NASButton) view.findViewById(R.id.nas_add_booking_add_button);
scanButton = (NASButton) view.findViewById(R.id.nas_add_booking_scan_button);
confirmationBox = (LinearLayout) view.findViewById(R.id.nas_add_booking_confirmation_box);
confirmationText = (NASHeaderAndSubtext) view.findViewById(R.id.nas_add_booking_confirmation_text);
confirmationBox.setVisibility(View.GONE);
bindButtons();
FontHelper.setFont(container, tabsActivity);
return view;
}
By debugging I can see that the editText is setting the text by breakpointing inside the overrided OnTextChanged.
This is the stacktrace from that breakpoint:
(NASEditText is my custom view)
Two problems / questions:
How can I prevent the activity/fragment/editText from filling in the text in the fields when fragment is restored?
Why is it filling in the same text for all fields?
Found the problem with help from a friend!
SaveEnabled is default true on editTexts in Android.
The solution is simply to set:
setSaveEnabled(false);
on your editText.
Turns out Android isn't very smart in how it restores state for views with identical IDs in the same hierarchy (even in parent views with different IDs). I just turned this off because I save my state in a ViewModel object and restore it from my fragment's onCreateView().
This is not the answer, but it fixes the problem:
As commented by #Slugge:
Override the onSaveInstanceState method in your custom editText and clear the text / do what you want from there.

How to set/change value while onCreate under TabLayout first Tab

i have try a lot of example or tutorial on tablayout, all work fine
(https://www.simplifiedcoding.net/android-tablayout-example-using-viewpager-fragments/, http://www.androidbegin.com/tutorial/implementing-fragment-tabs-in-android/)
but now i encounter 1 problem, which is i dont know how to set/change the TextView/ImageView while onCreate/onLoad
so far, what i able to do is, write all my code under onTabSelected, but this is not my solution because i cant show empty or static values on the 1st tab, then have to wait until click or slide again then only load the real data.
i'm sure it have a way or solution for my problem, can anyone share it to me (code/website)
or in order to have this Tab feature with viewpager contain recyclerview, Tablayout is not the right way to code, perhaps it have another more correct way to code.
Do these changes inside of onCreateView of fragment that you want
Example:
//Our class extending fragment
public class Tab1 extends Fragment {
//Overriden method onCreateView
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
//Change R.layout.tab1 in you classes
View view = inflater.inflate(R.layout.tab1, container, false);
TextView textView = (TextView) view.findViewById(R.id.you_textview_id);
textView .setText("Your text to show");
//Returning the layout file after inflating
return view;
}
}
The TextView need to be previous declared in tab.xml that you're inflating, in our example, tab1.

Android fragment: how to pass values in XML

I have a simple fragment with 2 TextView objects. The fragment has the corresponding Java class. How do I pass values from the activity layout XML to the fragment? I want to instantiate the same fragment multiple times with the TextView objects having different values.
So, the activity XML would be something like:
*
Thank you.
Everybody seems to ignore it but you can actually pass static arguments like a label through XML.
It's a bit complicated. First you need to declare the custom attributes you want to use in a file like attrs.xml, then you need to override Fragment.onInflate() to retrieve the value of these attributes.
The official Android documentation provides a simple example on how to retrieve a label from the XML layout to use it in a Fragment.
I guess that you are expecting some way of data binding in xml (for example like in wpf).
There is no data binding like that in android (at least not without third party libraries).
What you do have is your onCreateView () method of fragment.
There you catch reference to those TextView objects, like this:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment, container,
false);
TextView myTextView1 = (TextView)view.findViewById ("textView1");
TextView myTextView2 = (TextView)view.findViewById ("textView2");
return view;
}
There you can also set value of those textViews, or you can set it latter in code like this:
myTextView1.setText ("this is my textview1 test");
So, to conclude - there is no typical inside xml data binding in android, you have to find those views in fragment code and then manipulate with them.
EDIT:
if you have data somewhere in activity, and you want to pass it to your fragment when you create it, you can use fragment setArgument() function (and corresponding getArguments() ).
You have example here: Setting Fragment arguments from Activity - in the accepted answer.
EDIT 2:
According to new Data Binding Library it's possible to do binding like this:
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable name="user" type="com.example.User"/>
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#{user.firstName}"/>
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#{user.lastName}"/>
</LinearLayout>
</layout>
link: https://developer.android.com/tools/data-binding/guide.html
But note that it's still beta release.
It seems like you are going about using fragment wrong.
But nonetheless you can just use textview.setText in each fragments java class...
you want to pass data to the fragment and let the fragment use it. The following article describes the whole 9 yard:
http://developer.android.com/training/basics/fragments/communicating.html
In short:
sender to setArguments:
Bundle args = new Bundle();
args.putString("myText", aText);
f.setArguments(args);
the receiving Fragment to retrieve argument:
String text = getArguments().getInt("myText"); // myTextView.setText(...)
The following is an example of a Fragment. Notice the way you interact with the TextView. You just have to create as many fragments as you want and put them into an ArrayList so that you will be able to get information from all fragments.
public class Yourfragment extends Fragment {
private TextView mTextView;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.your_fragment, container, false);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
View _view = getView();
if(_view != null){
mTextView = (EditText) _view.findViewById(R.id.your_textView);
}
}
}
To answer your question,
you need to have a mainclass extending Activity class from which you will instantiate the fragmnet. And you need a fragment class with those two TextView objects ad the class variables with a parameterized constructor . So you need to maintain a Map which has key as the name of your fragment and textviewvalue1"+"textviewvalue2. So now while creating an instance of a fragment, you can send the value yiu have in the map as parameters to that fragment constructor.
Like this:
public class Yourfragment extends Fragment {
private TextView mTextView1;
private TextView mTextView2;
public Yourfragment(String txt1,String txt2){
super();
this.mTextView1.setText(txt1);
this.mTextView2.setText(txt2);
}
#Override public View
onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
//ur logic
}
#Override public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
//ur logic
}
} }
And in the place where you instantiate, use map.get( fragmentname).split("+")[0] and map.get( fragmentname).split("+")[1] as parameters to conatructor and set the title of fragment to fragmentname

Inflating same view multiple times -- faster way?

first question on SO, forgive me if I forget to include something.
In my activity, I have a function that loads a new activity that has a tabbed ViewPager with two fragments. From what I understand (or rather, from what I can tell) the activity does not load until both tabs have completed their onCreateViews() functions. Currently, this is taking between 500ms-2000ms which makes the application feel rather clunky. I believe this gives me two options:
Have the activity load and display the first tab once the first tab has finished it's onCreateView()
Preferably, speed up the loading of the second tab/fragment. What I'm doing is very slow and I'm looking for a better way to do it.
Here is an excerpt from my code for the second fragment (tab):
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View root_view = inflater.inflate(R.layout.stats_layout, container, false);
for (Map.Entry<String, int[]> entry : stats.entrySet()) {
String key = entry.getKey();
int[] value = entry.getValue();
if (value[2] == 1) {
LinearLayout ll_singles = (LinearLayout) root_view.findViewById(R.id.ll_singles_stats);
RelativeLayout rl_detail = (RelativeLayout) inflater.inflate(R.layout.rl_detail, ll_singles, false);
( (TextView) rl_detail.findViewById(R.id.tv_made) ).setText(Integer.toString(value[0]));
( (TextView) rl_detail.findViewById(R.id.tv_total) ).setText(Integer.toString(value[0] + value[1]));
( (TextView) rl_detail.findViewById(R.id.tv_percent) ).setText(MessageFormat.format("{0,number,0.00%}", (float) value[0] / (value[0] + value[1])));
ll_singles.addView(rl_detail);
}
}
Without getting too specific on my entire layout (unless someone asks), I inflate a single RelativeLayout (rl_detail) many (50+) times and add it to four different LinearLayouts (in this excerpt, ll_singles).
I know findViewById() is an expensive action and I have to think there is a way to avoid the findViewById() that I do every time I inflate the exact same view when I change the text for the TextView.
I have explored asynctasks (haven't been able to find an example that inflates views in the background -- it sounds like it isn't possible) and have considered using a ViewHolder, but that seems exclusive to ListViews.
Any ideas?

Android: How to get a view given an activity inside a normal class?

I have a normal class (not an activity). Inside that class, I have a reference to an activity.
Now I want to access a view (to add a child) contained in the layout xml of that activity.
I don't know the name of the layout file of that activity. I only know the ID of the view, which I want to access (for example: R.id.my_view).
How can I do that?
Regarding the NullPointerException (which you should add to the question), always make sure you've called setContentView() in your Activity before trying to access a View defined in XML. Example usage:
public class MainActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
...
}
...
}
Then, somewhere,
ViewGroup group = (ViewGroup) context.findViewById(R.id.group); // In your example, R.id.my_view
The reason you need to have called setContentView() is that before it's called, your View(Group) doesn't exist. Because findViewById() is unable to find something that doesn't exist, it returns null.
As simple as that!
View view = activity.findViewById(R.id.my_view);
In case of the Layout:
LinearLayout layout = (LinearLayout) activity.findViewById(R.id.my_layoutId);
And to add the Views:
layout.addView(view);
You could make your method accept an Activity parameter and then use it to find the view by id.
Ex:
public class MyClass{
public void doSomething(Activity context){
TextView text=(TextView)context.findViewById(R.id.my_textview);
}
}
Then in your activity:
obj.doSomething(YourActivity.this);

Categories

Resources