Layout in Dynamic Fragments - android

I'm writing a calculator application in which I would like to be able to switch between 4 modes of calculation: Decimal, Binary, Octal, and Hex. In order to manage the different UIs for the different modes, I have 4 Fragment subclasses in my Activity. Each Fragment has its own XML layout file, in addition to the main XML file for the Activity. I found a guide on the Android Developer site for inflating layouts for Fragments, and I've followed that guide. However, I would like to add listeners and so on to the various components of the layouts, preferably within the onCreateLayout method of the Fragment, or somewhere else where I could do it easily and minimize code duplication.
It appears, however, that when I try to call findViewByID to access one of the inflated Views (after I've called LayoutInflater.inflate, obviously), I get a null return value. This issue occurs whether I call findViewByID from within onCreateLayout or from elsewhere in the Activity (after the Views have, theoretically, been created). What's going wrong here?
One issue I think might be a problem is that I've overloaded the names of the Views between the various Fragment layouts. For example, the "1" button in the Binary layout has the same ID as the "1" button in the Hex layout. Is this allowed, assuming the Binary and Hex layouts are never both part of the Activity at the same time?
Thanks.

I think same id in different layout is not problem in Fragement. First you have to catch the inflated view then find whatever inside this. For example --
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
view = inflater.inflate(R.layout.frg1, container, false);
android.util.Log.v("", "!!!!!!!!!! Frg1 !!!!!!!!!");
Button b = (Button) view.findViewById(R.id.b1);
b.setOnClickListener(new View.OnClickListener(){
public void onClick(View v) {
Toast.makeText(getActivity(), "here", Toast.LENGTH_SHORT).show();
}
});
return view;
}

Related

How onCreateView works

I started a TabLayout Activity, which includes the following code to create the fragment:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_find, container, false);
TextView textView = (TextView) rootView.findViewById(R.id.section_label);
textView.setText(getString(R.string.section_format, getArguments().getInt(ARG_SECTION_NUMBER)));
return rootView;
}
I've read the official documentation and still unsure how it works. If somebody could explain in detail how each part here is working that would be great.
Edit: Mainly referring to View rootView = inflater.inflate(R.layout.fragment_find, container, false); what each of these 3 parameters are doing and how inflater.inflate() is working here.
OK, here we go.
The process of inflating is simply creating your view explicitly instead of doing this implicitly, this is by using this:
public void onCreate(){
setContentView(R.layout.your_layout);
}
Compare with this question.
Now with the arguments. Compare this with this section.
R.layout.fragment_find returns ID of a fragment used somewhere in the code. R is a dynamic android class used for manipulating some of your app's resources such as views, strings etc. Compare.
container is a root from some ViewGroup. So you hgave a group of, say, buttons doing common things (for example choosing some colour in your application), and they all have same parent, in your case called a container.
attachToRoot is the last argument. According to docs:
If false, root is only used to create the correct subclass of LayoutParams for the root view in the XML.
So it is not attached to the parent we talked about in last point. Compare here.
I hope this helped.
onCreateView():
After the onCreate() is called (in the Fragment), the Fragment's onCreateView() is called. You can assign your View variables and do any graphical initialisations. You are expected to return a View from this method, and this is the main UI view, but if your Fragment does not use any layouts or graphics, you can return null (happens by default if you don't override).
Here, it's a method of the lifecycle for Fragment.

Change fragment layout dynamically instead of replacing fragments Android SDK

I'm trying make an app that displays a big amount of text and images in a specific layout when the user clicks on a corresponding listview item. Since I want specific .xml layouts for separate 'chapters', I want only the layout of a fragment to change to the corresponding chapter.
Googling tells me I can do this with fragments, but as far as I understand, I need separate fragment classes and .xml layouts for every chapter I want to implement. With 2 or 3 chapters, that can be done, but with more chapters that will become I thought, isn't it simpler to just keep two fragments (one with a listview and one with the chapter text), but dynamically change the layout of the second fragment if the user clicks on an item in the listview.
Can this be done with some code like this (just thinking out loud)?
Int[] layouts = {
{R.layout.chapter1, R.layout.chapter2, R.layout.chapter3}
};
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
index = intent.getIntent("index", 0);
return inflater.inflate(layouts[index], container, false);
}
Or is there another way to achieve this?
Fragments at their core are View wrappers that contains states of Views. You can use them for other purposes like resource handling, but mostly they're just segments of an Activity state. It most likely would not be a good idea to have a Fragment for every single chapter unless each chapter has their own unique state that needs to be kept. However, if the Views are static, then a single Fragment is all you really need.
In this case, you simply have to have a method like this:
public void setChapter(int chapter)
{
Context ctx = getActivity();
if(ctx == null) {
// detached from Activity, so bail.
return;
}
if(chapter > layouts.length) {
return;
}
ViewGroup container = (ViewGroup) getView().findViewById(R.id.chapter_container);
container.removeAllViews();
View chapterInflater = LayoutInflater.from(ctx).inflate(layouts[chapter], container);
}
So this will wipe out all views currently in your container, inflate a new one, and put it in the container (most likely a simple FrameLayout).
The code in the original question can be used to initialize a Fragment if you want to open it at a certain point. onCreate_() methods are called only when the items is being "built" or "created". onCreateView() won't be called again though, so you need a method to change the layout once it's set.

How do I duplicate fragments?

My FragmentActivity loops and creates 8 Fragments from the same xml and activity. The fragment has a TextView, by passing parameters to the Fragment, I want to display different text inside each TextView of the Fragments. With this method, I can save creating 139 identical fragments with different texts.
Problem, all 8 fragment's TextView changes when I setText(), because they all share the same template (xml and activity).
Solution - see my answer below.
Extremis
It's because when you duplicate your Fragment, you refer to the same view for each fragment you create. You have to change the id of the fragment. If you don't do that you call the same fragment all the time.
Final Answer : On onCreateView method
private static int id = 0;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
LinearLayout mLinearLayout = new LinearLayout(this);
TextView mTextView = new TextView(this);
mTexTView.setId(Id);
id++;
mLinearLayout.addView(mTextView);
return mLinearLayout;
}
After you can use the id of your textview and set the text.
Okay, so I've learned that something was wrong in my code when I tried to duplicate fragments in th way attempted above.
My Solution
I created a new dummy Android project and selected the Navigation type as Scrollable Tabs + Swipe.
I then learned that it had 1 activity:
main.java - whcih extends:
FragmentActivity
and, 2 layout's:
main.xml - which contained:
<android.support.v4.view.ViewPager> , and
<android.support.v4.view.PagerTitleStrip>
Fragment.xml - which contained:
TextView
By adjusting the adapter, I was able to create unique Fragments based on the Same layout (xml).
So ultimately - Create a new dummy project with the Scrollable Tabs + Swipe and adjust your code based on that example.
Hope this help.
Extremis

Buttons using onClickListener

am new to android
I have seen many examples on creating buttons, but i just can't get what does each line mean :(
take the following piece of code as an ex.
connect = (Button) findViewById(R.id.button_connect)
connect.setOnClickListener(connectListener)
private OnClickListener connectListener = new OnClickListener() {
public void onClick(View v) {
Log.i("CONNECT PRESSED", "press")
// ....
// ....
// ....
};
what i know is that the first line Defines a button, but wht is findViewbyId?
i know the second line
but then when defining the listener, what's the log.i?
nd r "connect pressed" and "press" just labels for the button? f so why there r two for a single button...
You should have an additional Button connect; before those lines.
connect = (Button) findViewById(R.id.button_connect) // findViewById() in layman term it means, finding view by id. Which also means finding the view(button/textview/edittext) by ID(value you stated in your main.xml for the view. e.e. android:id=#+id/"")
connect.setOnClickListener(connectListener) //listens to a click when clicked
private OnClickListener connectListener = new OnClickListener() { //if button of android:id="button_connect" is clicked, Do this method.
public void onClick(View v) {
Log.i("CONNECT PRESSED", "press") //prints message in your logcat
// ....
// ....
// ....
};
If you still don't understand what does findViewById(), just think of it this way. View is man. Id is name. So in the end you are finding the man by name("Whatever this is")
In Android you normally define the layout of an Activity in an XML file. Each View element in a layout that you want to interact with in code needs an id. In you example the layout XML file needs to have a button with the id button_connect.
In the onCreate() method of an Activity you normally call setContentView() and pass it the layout you want to use in this Activity. E.g. setContentView(R.layout.my_layout); where your layout file's name is my_layout.xml.
The setContentView() method builds up the defined layout as objects and with findViewById(R.id.button_connect) you get a reference to a Button object from this layout whose id is button_connect.
Log.i() is simply logs the message "press" under the tag "CONNECT PRESSED" in the log cat.
It seem to be you didn't read basic things about android app development. Android Developers website providing information to learn android app development with good examples and tutorials. You are asking very basic things by just copying the code from tutorials.
Actually its not the right place for this kind of questions. First do practice by reading tutorials around the web.
Coming to your doubts regarding code you posted here, those are very basic things.
findViewById() finds a View by field Id, which is declared in XML layout file as below
Log.i() is LogCat info message displayed in your logcat window when debugging is enabled in your app.
in your example you probably have defined an xml layout file as the style of your activity with setContentView(R.layout.myXMLLayout);
If not, findViewById(R.id.button_connect) will fail.
R.id.button_connect refers to an id created in your xml layout.
There has to be a line android:id="#+id/button_connect" in a < Button > tag.
findViewById finds this Button (which is more genereally a view, which is why you have to cast it to a Button with the (Button) before findViewById(...) ). You then refer to exactly the button you've put in your xml.
Log.i("CONNECT PRESSED","press"); isn't necessary at all. It's just logging the press of the button and displays it in the log cat. It can be removed without any further impact. This is for debugging only and should be removed for any final (public) versions of your code.

findViewByID(R.layout.skeleton_activity) returns null

I am trying to register a context menu in a skeleton app's OnCreate():
/** Called with the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Inflate our UI from its XML layout description.
setContentView(R.layout.skeleton_activity);
View v = findViewById(R.layout.skeleton_activity);
registerForContextMenu(v);
// Find the text editor view inside the layout, because we
// want to do various programmatic things with it.
mEditor = (EditText) findViewById(R.id.editor);
// Hook up button presses to the appropriate event handler.
((Button) findViewById(R.id.back)).setOnClickListener(mBackListener);
((Button) findViewById(R.id.clear)).setOnClickListener(mClearListener);
mEditor.setText(getText(R.string.main_label));
}
The debugger tells me that findViewById(R.layout.skeleton_activity) returns null.
#CommonsWare solution to a similar post is to Wait until onFinishInflate(). However, in the sample project he provides, it doesn't seem that he waits until onFinishInflate.
My questions:
Can registerForContextMenu() wait
until onFinishInflate()?
If so, how do I do so?
This line is not correct its asking for id and you are providing layout
View v = findViewById(R.layout.skeleton_activity);
Instead if you want to have object of your root layout element then provide it some id and then try something like this
View v = findViewById(R.id.root_element);
I think you should use
View v = findViewById(R.id.skeleton_activity);
instead.
For the 2nd question, sorry, I 've no idea. Hope to see someone else's answer.
You shouldn't need to wait for the content to inflate in an Activity.
One problem is that findViewById takes an ID (R.id....) when you provide it with a layout (R.layout...). Can you try the following instead, to reference the Activity's root view?
setContentView(R.layout.skeleton_activity);
View content = findViewById(android.R.id.content);
registerForContextMenu(content);
i think the code you have shown is very confusing. Here is a good article http://blog.sptechnolab.com/2011/02/10/android/android-contextmenu-submenu/. In my case it works, i hope you can solve your problem.

Categories

Resources