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
Related
This is a pretty straightfoward question... i would like to use very simple fragments and tell them which layout to inflate without the need to create a class for each fragment and override the method onCreateView
in simple words i would like to do:
Fragment f = new Fragment();
f.loadfromlayout(R.layout.layout);
is there any way to achieve that?
the closest i get is:
new Fragment() {
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.activity_send_screenshot_step1, container, false);
}
}
======================UPDATE===================
Just to clarify a bit more my requirements. What i'm trying to achieve is this:
https://developer.android.com/training/animation/screen-slide
https://developer.android.com/training/animation/anim_screenslide.mp4
Use ViewPager to create a step-by-step wizard
as shown in the official android documentation my example will load a very simple layout for each "step" (every step is a fragment)... and in order to get this using the default android components i need to create a new class extending Fragment for every single step in my wizard all of them are exaclty the same thing just specifying a different layout in the onCreateView
that is very unnelegant and a lot of repetitive code in my opinion. i would like to avoid
As many people pointed in the comments this behavior was not originally desinged to happen in android.
I found a solution that will work for my case and still fine.
public class GenericFragment extends Fragment {
public static GenericFragment newInstance(#LayoutRes int layout) {
Bundle b = new Bundle();
b.putInt("layout", layout);
GenericFragment g = new GenericFragment();
g.setArguments(b);
return g;
}
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
return inflater.inflate(getArguments().getInt("layout"), container, false);
}
}
this way i need only 1 single class extending Fragment and i can have as many pages with different layouts i want in my wizards... as long as the pages dont have "specific behavior"
I have implemented swipe in tablayout of my activity call Performance_Medicine
public class Performance_Medicine extends Fragment{
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
//Returning the layout file after inflating
//Change R.layout.tab1 in you classes
return inflater.inflate(R.layout.performance_medicine, container, false);
}
}
Now, I am trying to implement cardview in same activity. But getting error
like below image
You are getting the error because you are trying to pass an instance of Performance_Medicine which extends Fragment. You need to pass in a context which you can do via this.getActivity() or this.getContext(). If you can pass the application context via a singleton or this.getActivity().getApplicationContext() then you may be better off memory wise.
Remember that a Fragment has its own lifecycle, but it runs in the context of its host Activity, that means you can not use 'this' for getting the Context, instead you need to use getActivity(). Also, as sam_c says, in your onCreate() method, the last line of code must be the 'return...' since this method has the return type 'View', and if you call the return statement, the method won't execute anything after this. Hope this helps to clarify.
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.
This code works:
public static class PlaceholderFragment extends Fragment {
public PlaceholderFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_detail, container, false);
Intent intent = getActivity().getIntent();
String weather = intent.getStringExtra(Intent.EXTRA_TEXT);
if(weather != null) {
TextView textViewWeather=(TextView)rootView.findViewById(R.id.weatherText);
textViewWeather.setText(weather);
BUT if you replace, in the line
(TextView)rootView.findViewById(R.id.weatherText);
rootView by findView() or getActivity, it returns null so the next line creates a run time fatal error which halts the program.
I don't understand why. I thought that the context is the activity?! I'm confused,and can't find a good answer via android developer,so here I am...
Thanks in advance to whoever helps!!
when you call :
View rootView = inflater.inflate(R.layout.fragment_detail, container, false);
TextView textViewWeather=(TextView)rootView.findViewById(R.id.weatherText);
the rootView now contains the views that are defined in fargment_detail.xml .
and weatherText is one of them.
but when you call getActivity().findViewById() or findViewById() you want to find the weatherText inside xml file of activity and there is no weatherText there so it will retun null
This line gets the element with id weatherText from its rootView. Which is nothing but your fragment xml file
TextView textViewWeather=(TextView)rootView.findViewById(R.id.weatherText);
Now if you are replacing above code with below
TextView textViewWeather=(TextView)getActivity().findViewById(R.id.weatherText);
now the parent Activity in which this fragment is hosted which has TextView and id weatherText will be searched by framework. Which is obvious is not present at all.
If you remove the rootView you are calling it directly on the activity so those two suggestions are equal (and activity is indeed the context).
But the activity doesn't know about the layout yet, you just inflated it from xml but it has not been given to the activity yet, and therefore can't be found. You do that by returning it from the onCreateView call you are in in your example code.
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");.
}
});