android: creat layout dynamically and setContentView it dynamically - java

Suppose there is an Activity called "m1" and there are two layouts called "m2" and "m3" both have few buttons is dynamically how i can setContentView dynamically whay

You have a method to set view to the setContentView
So you can pass the root parent view to this method to achieve your requirement.

You can pass layout Resource ID or View in setContentView(); method.
try this..
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
LayoutInflater mInflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if(viewlayout1){
view = mInflater.inflate(R.layout.layout1,null);
}else{
view = mInflater.inflate(R.layout.layout2,null);
}
setContentView(view);
/*******************/
}

The view hierarchy can have only one root. What setContentView() essentially does is that it sets the root view.
In your case,
Method 1
You'll have to either make one of the layouts as the root and add the other as a child. And call setContentView(root).
Or
Method 2
Create a dummy container layout. Set that as root.
And add both your layouts as children to that container layout.

Related

How to create a dynamic UI with Kotlin in Android Studio

create widget at runtime as texts and buttons, with kotlin language
For example, when clicking a button, a new text is created
The answer for XML-based UI:
To add a view programmatically on Android, you can use the addView method of a ViewGroup. Here are the basic steps:
Get a reference to the parent ViewGroup where you want to add the new view. You can do this by calling findViewById on the parent Activity or Fragment.
Create a new instance of the View you want to add to the parent ViewGroup. You can do this by calling the constructor of the View class that matches the type of View you want to create.
Set any necessary properties on the new View, such as its layout parameters or content.
Add the new View to the parent ViewGroup by calling the addView method on the parent ViewGroup and passing in the new View.
Here's an example of how to add a TextView to a LinearLayout programmatically:
val linearLayout = findViewById(R.id.linear_layout) // get a reference to the parent LinearLayout
val textView = TextView(this) // create a new TextView in Activity
// or TextView(requireContext) in Fragment
textView.text = "Hello, world!" // set the text of the TextView
linearLayout.addView(textView) // add the TextView to the LinearLayout
lets assume you have a ViewGroup such as LinearLayout and lets name it group
and you have a button.
Based on this assumption. I would do the following
mButton.setOnClickListener{
group.addView(TextView(context)
.also{
it.text = "your text"
})
}
of course you will have to work on positioning it too

Why do we need to Inflate a layout and attachToRoot in Android?

I was given this code:
override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater!!.inflate(R.layout.fragment_wednesday, container, false)
}
and I don't understand why we need to Inflate a layout and write attachToRoot value.
btw, why do we need a viewGroup?
A layout definition is just some XML data but to really show a layout it must be converted to a tree of objects. The inflater does that.
A container (ViewGroup) is necessary to control where (in a larger tree of view objects) the inflated subtree should be placed.
consider this code
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup fragment_container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.example_fragment, fragment_container, false);
}
The second parameter fragment_container is a container(framelayout) with id fragment_container that activity uses to add view of fragment in its layout.
No if we read source code of inflate method of LayoutInflater class, we get this( i removed unnecessary shit here to make you understand code better)
// The view that would be returned from this method.
View result = root;
// Temp is the root view that was found in the xml.
final View temp = createViewFromTag(root, name, attrs, false);
Firstly, it creates a temp view from the supplied root.
In case attachToRoot is false, it does this :
// Decide whether to return the root that was passed in or the
// top view found in xml.
if (root == null || !attachToRoot) {
result = temp;
}
In case attachToRoot is false, it simply returns the root of the fragment's xml, i.e. the container parameter is just used to get layoutParams for fragment's root view (since it doesn't have a root, so it needs params from somewhere).
In case attachToRoot is true, it does this :
// We are supposed to attach all the views we found (int temp)
// to root. Do that now.
if (root != null && attachToRoot) {
root.addView(temp, params);
}
It adds the temp view created above to the root view (i.e. container).
The main difference between the "third" parameter attachToRoot being true or false is this.
true : add the child view to parent RIGHT NOW
false: add the child view to parent NOT NOW. Add it later. `
When is that later?
That later is when you use for eg parent.addView(childView)
A common misconception is, if attachToRoot parameter is false then the child view will not be added to parent. WRONG
In both cases child view will be added to parentView. It is just the matter of time.
inflater.inflate(child,parent,false);
parent.addView(child);
is equivalent to
inflater.inflate(child,parent,true);
NOTE !! NOTE !! NOTE !!
You should never pass attachToRoot as true when you are not responsible for adding the child view to parent.
Eg When adding Fragment
public View onCreateView(LayoutInflater inflater,ViewGroup parent,Bundle bundle)
{
super.onCreateView(inflater,parent,bundle);
View v = inflater.inflate(R.layout.image_fragment,parent,false);
return v;
}
now , if you pass third parameter as true you will get IllegalStateException because of the following piece of code.
getSupportFragmentManager()
.beginTransaction()
.add(parent, childFragment)
.commit();
Since you have already added the child fragment in onCreateView() by mistake. Calling add will tell you that child view is already added to parent , hence IllegalStateException. This Exception comes from the following piece of code which can be found while inspecting inflate method in LayoutInflater class
if (child.getParent() != null) {
throw new IllegalStateException("The specified child already has a parent. " +
"You must call removeView() on the child's parent first.");
}
Here you are not responsible for adding childView, FragmentManager is responsible. So always pass false in this case

Does fragment call the onCreate method of parent activity?

I have an activity with a viewPager inside of it, and a static ArrayList of integers that I am shuffling using Collections.shuffle(list) in the activity's onCreate method, this viewPager's fragments are using the ArrayList in parent activity.
The problem is that whenever a new fragment instantiated of the viewPager the onCreate method of parent activity is called, and I don't want that to happen because I want the list to have the same data in all fragments and not reshuffled. Do fragments call the onCreate method of their parent activities everytime there is a new instance? if Yes how can I work around this to keep the list from shuffling every time?
CODE:
Activity Code:
public static final ArrayList<Integer> IDs = new ArrayList<>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
IDs.add(0);
IDs.add(1);
IDs.add(2);
Collections.shuffle(IDs);
setContentView(R.layout.activity_walkthrough);
pager = (ViewPager) findViewById(R.id.pager);
adapter = new ScreenSlidePagerAdapter(getSupportFragmentManager());
pager.setAdapter(adapter);
Fragment Code:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = (View) inflater.inflate(
R.layout.fragment_walkthrough, container, false);
final TypedArray imgs = getResources().obtainTypedArray(R.array.walkthrough_images);
ImageView imageView = (ImageView) v.findViewById(R.id.image);
if (page == 0) {
imageView.setImageResource(imgs.getResourceId(Walkthrough.IDs.get(0), 0));
} else if (page == 2) {
imageView.setImageResource(imgs.getResourceId(Walkthrough.IDs.get(1), 0));
} else {
imageView.setImageResource(imgs.getResourceId(Walkthrough.IDs.get(2), 0));
}
return v;
}
Now I want the ArrayList "IDs" to always have the same data and order when ever I instantiate a new fragment but it is not working, every time I create a new fragment the method onCreate gets recalled and a reshuffle happens!
Fragments are added to activity and therefore fragments get affected by activity.
Activity can cause calling any fragment callback method, but fragment can't
The lifecycle of the activity in which the fragment lives directly affects the lifecycle of the fragment.
For example, when the activity receives onPause(), each fragment in the activity receives onPause().
Fragments have a few extra lifecycle callbacks, however, that handle unique interaction with the activity in order to perform actions such as build and destroy the fragment's UI.
These additional callback methods are like onAttach(), onCreateView(), etc.
It'll clears the somewhat relation between fragment and activity.
Thanks

Adding methods after fragments

I have a fragment that is a "timer" that I can add anywhere. In the fragment I change a textView programatically, and it runs beautifully. My problem is when it comes to using a view from the layout inflated by the constructor(? Not sure if that's the right terminology) in another method below it.
public class Timer_fragment extends android.support.v4.app.Fragment {
int testpins;
String testedpin;
TextView text;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.timer_frag, container, false);
TextView text = (TextView) v.findViewById(R.id.pwd_status);
text.setText("Setting text in fragment not main");
/* set the TextView's text, click listeners, etc. */
updateStatus();
return v;
}
All of that code works with no errors but when I try to add this method:
private void updateStatus() {
TextView text = (TextView) findViewById(R.id.pwd_status);
testPin();
text.setText(testedpin);
}
I get a red line under findViewById saying The method findViewById(int) is undefined for the type Timer_fragment.
I thought about inflating the view in all of my methods and not returning them, but surely that would affect performance somehow right?
Just tried inflating the layout before using the view but I get an error on the word inflater and container saying that they can't be resolved.
Am I going about this correctly?
You already have a member variable in the scope of your Fragment called text. Don't re-declare it in your methods, just assign it.
text = (TextView) v.findViewById(R.id.pwd_status);
and
private void upateStatus() {
testPin();
text.setText(testedpin);
}
The method 'findViewById' is provided by the activity. While this class extends Fragment, you will not have access to activity related method calls unless you provide the activity to the fragment. Check out: http://developer.android.com/reference/android/app/Activity.html#findViewById(int)
Basically, either pass in the instance of the activity to the Timer_fragment:
private final Activity _activity;
Timer_fragment(Activity activity)
{
_activity = activity;
}
...
private void updateStatus()
{
TextView text = (TextView) _activity.findViewById(R.id.pwd_status);
testPin();
text.setText(testedpin);
}
Or set the text of the view from within whichever activity is being used, and not from within the timer class.
Just replace findViewById with getActivity().findViewById.
findViewById method is defined inside the Activity class. Fragments aren’t activites. But the fragment can get a reference to the Activity that added it to a screen using the method getActivity.

Android Layout XML file with class

I created a class that extends RelativeLayout.
I also created a xml layout file.
How can I 'connect' between them as I connect Activities with their xml files
(setContentView(R.layout.main);)
Thanks!
I mean you can use LayoutInflater to load the xml in the relative layout, but am not sure that what you should be doing. I am not sure what your trying to do but your wrapping your layout inside another view by doing this. When you can just load the xml straight into your view using the same tactic. So you lose one level of complexity.
LayoutInflater inflater = (LayoutInflater)getContext().getSystemService
(Context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.view,null);
addView(view);
You can inflate the layout using the LayoutInflater right in your constructor.
public class RelSub extends RelativeLayout {
public RelSub(Context context) {
super(context);
// TODO Auto-generated constructor stub
LayoutInflater inflater = (LayoutInflater) context.getSystemService(LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.main, this);
}
}

Categories