Android get child from FrameLayout - android

If I create two classes, a Parent class which extends FrameLayout, and a Child class that extends View, and then use XML to initialise them. Is it possible to get child elements from the Parent class constructor? If i use getChildAt() , I always get null, since the activity is still not created.
<com.example.Parent
android:layout_width="match_parent"
android:layout_height="200dp"
android:layout_centerInParent="true">
<com.example.Child
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.example.Child
android:layout_width="match_parent"
android:layout_height="match_parent" />
</com.example.Parent>
Parent and Child classes
public class Parent extends FrameLayout {
public Parent(#NonNull Context context) {
super(context);
this.getChildAt(0); // return null
}
...
}
public class Child extends View {
...
}

Since you are calling getChildAt at the construction of your FrameLayout you are getting null values (your children are still not fully attached to the view). One solution would be to overwrite onLayout() or onMeasure() to get your childs.

Before inflating you can not get child view form Parent.
But you can do it dynamically but is also work in same way like , you have to add views manually to Parent view.
And then you can get child views form Parent View.

Related

Retain view bounds of dynamically added textview on fragment reload

There is a Fragment named FragmentA that has a RelativeLayout with an ImageView behind it. (Say 4)Textviews are dynamically added to the rlParentView This layout resides inside a Fragment layout.
The Textviews are draggable inside the parent layout.
Another Fragment is loaded in the same activity and when FragmentA is reloaded, now the dynamically added textviews are lost so how can I retain the dynamically added TextViews with their text and other bounds.
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="0.85"
android:layout_margin="5dp"
android:id="#+id/rlParentView">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/background_image" />
</RelativeLayout>
Dragable TextView are added dynamically like this:
View inflateLayout=mInflater.inflate(R.layout.text_drag_layout,mParentContainer,false);
TextView draggableView= (TextView) inflateLayout.findViewById(R.id.draggableView);
rlParentView.addView(inflateLayout);
draggableView.setText(Some_Text_here);
OnDragTouchListener listener=new OnDragTouchListener(draggableView, rlParentView,
new OnDragTouchListener.OnDragActionListener() {
#Override
public void onDragStart(View view) {
}
#Override
public void onDragEnd(View view) {
}
}
);
draggableView.setOnTouchListener(listener);
I haven't tried it, but here's an idea:
In onSaveInstanceState() of Fragment A, save the positions (and whetever else) of the TextViews inside their parent. Something like:
class ViewPositionInfo implements Serializable {
String text;
int xPositionInParent;
int yPositionInParent;
// ... other variables you need to store
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
List<ViewPositionInfo> positionInfos = new ArrayList<>();
// iterate over the views and add them inside the list
outState.putExtra("positions", positionInfos);
}
Then, when the fragment is re-created, read this information in onCreateView(), create TextViews with those attributes and add them to the parent layout.
The solution above has a drawback. When rotating the screen, the width / height will be different than before, so saving x and y positions of the the text views inside their parent might not be a good idea. You might need to save a relative position, i.e. a percentage. But first things first - make the simple case work (as explained above) and then think about this one.

App Crashes When Trying To Move View To Another View Group [duplicate]

I want to implement custom ViewGroup in my case derived from FrameLayout but I want all child views added from xml to be added not directly into this view but in FrameLayout contained in this custom ViewGroup.
Let me show example to make it clear.
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<FrameLayout
android:id="#+id/frame_layout_child_container"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<FrameLayout
android:id="#+id/frame_layout_top"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</merge>
And I want to redirect adding all child view to FrameLayout with id frame_layout_child_container.
So of course I overrode methods addView() like this
#Override
public void addView(View child) {
this.mFrameLayoutChildViewsContainer.addView(child);
}
But for sure this doesn't work because for this time mFrameLayoutChildViewsContainer is not added to the root custom view.
My idea is always keep some view on on the top in this container frame_layout_top and all child views added into custom component should go to frame_layout_child_container
Example of using custom view
<CustomFrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"/>
</CustomFrameLayout>
So in this case TextView should be added to the frame_layout_child_container
Is it possible to delegate adding all views into child ViewGroup like I described.
I have other ideas like using bringToFront() method every time view is added to keep them in correct z-axis order or for example when view is added, save it to array and than after inflating custom view add all views to this child FrameLayout
Suggest what to do in this case in order not to hit performance with reinflating all layout every time new view is added, if it is possible to implement in other way.
Views inflated from a layout - like your example TextView - are not added to their parent ViewGroup with addView(View child), which is why overriding just that method didn't work for you. You want to override addView(View child, int index, ViewGroup.LayoutParams params), which all of the other addView() overloads end up calling.
In that method, check if the child being added is one of your two special FrameLayouts. If it is, let the super class handle the add. Otherwise, add the child to your container FrameLayout.
public class CustomFrameLayout extends FrameLayout {
private final FrameLayout topLayout;
private final FrameLayout containerLayout;
...
public CustomFrameLayout(Context context, AttributeSet attrs) {
super(context, attrs);
LayoutInflater.from(context).inflate(R.layout.custom, this, true);
topLayout = (FrameLayout) findViewById(R.id.frame_layout_top);
containerLayout = (FrameLayout) findViewById(R.id.frame_layout_child_container);
}
#Override
public void addView(View child, int index, ViewGroup.LayoutParams params) {
final int id = child.getId();
if (id == R.id.frame_layout_top || id == R.id.frame_layout_child_container) {
super.addView(child, index, params);
}
else {
containerLayout.addView(child, index, params);
}
}
}

Convert view into view that extends view

Is there a possibility that in the xml resource layout to have a base view and when inflate it to convert it to a specific view ?
For example having a custom view called MyCustomView that extends EditText, and some views that extends MyCustomView like MyCustomViewNumber or MyCustomViewPassword and a layout like this :
<com.example.MyCustomView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
.....>
</com.example.MyCustomView>
Is it possible that after I inflate this xml, MyCustomView to became one of MyCustomViewNumber or MyCustomViewPassword (inherit all attributes from those two). MyCustomViewNumber will be an EditText(better said a MyCustomView) that in the constructor method has setInputType to number.
View baseView = LayoutInflater.from(getContext()).inflate(R.id.my_layout, container, false);
baseView = new MyCustomViewNumber(getContext()). //with this line I want that my view from the layout to take all attributes from MyCustomViewNumber.
Recapitulating:
public class MyCustomView extends EditText
public class MyCustomViewNumber extends MyCustomView {
ctors > this.setInputType("number");
}
public class MyCustomViewPassword extends MyCustomView{ ctors > same as above }
Inflate MyCustomView. Set the inflated view to MyCustomViewNumber or MyCustomViewPassword. Is it possible ?
Basically I do this because I need the "layoutParams". I know that I could get the layout params from the inflated view, remove it and then add the new one with that parameters.
No, the class whose fully qualified name you use in your XML is instantiated by the system, and thus must be a concrete class.

Add some element in CustomView (which is in fragment)

This sound simple and probably answer is trivial.
I have SomeCustomView class which extending RelativeView. This SomeCustomView have simple addShapeInCustomView():
public class SomeCustomView extends RelativeLayout {
//constructor etc.
public void addShapeInCustomView(){
View testView = new View(ctx);
testView.setLayoutParams(new LayoutParams(50, viewHeight));
ViewHelper.setTranslationX(testView, 20);
testView.setBackgroundColor(Color.GREEN);
addView(testView);
invalidate();
}
}
Of course I added this in my xml layout:
<com.example.test.app.lib.SomeCustomView
android:id="#+id/someCustomView"
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_margin="5dp"
android:background="#color/darkblue">
Then in Fragment I calling addShapeInCustomView():
public View onCreateView(...){
//inflate etc.
someCustomView = (SomeCustomView) view.findViewById(R.id.someCustomView);
someCustomView.addShapeInCustomView();
}
SomeCustomView is creating correctly. No errors. But testView from addShapeInCustomView() isn't visible.
What am I doing wrong? What if I want add some elements after initialization (and after onDraw())? I should call addShapeInCustomView() in other moment of Fragment lifecycle (tested and nothing happens)?
If I call addShapeInCustomView() with 200ms of delay it's works perfectly. someView shows up. But obviously it's strange work around.
You should use requestLayout() in place of invalidate(). Invalidating just redraws the current layout, whereas requestLayout() will re-measure and layout the child views, then draw them.

Add & remove custom layout element in Activity Java code

I have a main activity
public class MainActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//HOW TO: dynamically add or remove <com.my.custom.MyCustomLayout>
}
}
The content of the above main Activity is:
main.xml
<FrameLayout ...>
<LinearLayout ...>
<com.my.custom.MyCustomLayout
android:id="#+id/custom">
<FrameLayout>
As you see above, I have a custom layout element, which is a Java class extends LinearLayout like following:
public class MyCustomLayout extends LinearLayout{
...
}
In my activity java code, I would like to dynamically add or remove the custom layout element<com.my.custom.MyCustomLayout> in main.xml layout.
How to do it in My activity Java code?
Create a different layout file with your custom view like:
difflayout.xml:
<com.my.custom.MyCustomLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/custom">
Take a reference of your container LinearLayout on your code section. Use LayoutInflater and addView() and removeAllViews() of the ViewGroup class(here your LinearLayout)
First consider if you really want to remove the view from the layout or just completely hide it. You need to have a very good reason to go for the latter.
To just hide the view you would do in your activity
findViewById(R.id.custom).setVisibility(View.GONE) // to hide
// or
findViewById(R.id.custom).setVisibility(View.VISIBLE) // to show
If you really want to completely remove the view from the layout, you can
View customView = findViewById(R.id.custom);
ViewGroup parentView = (ViewGroup) customView.getParent();
parentView.removeView(customView)
you must have defined , id for the custom layout. use this id in java code
example : customLayout = (LinearLayout)findViewById(id);
now with customLayout call the layout

Categories

Resources