resize relative layout after adding child view - android

I got a custom view extending RelativeLayout.
After inflating it with an xml layout I want to add another view to it.
I want to add the view above the existing one.
That seems to work but the RelativeLayout does not resize itself.
It looks like the older contents get overwritten, or maybe scroll down, where they
are not visible.
I create my custom RelativeLayout with:
public class BottomBarEdit extends RelativeLayout {
private Context context;
public BottomBarEdit(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
this.context = context;
View.inflate(context, R.layout.lay_bottom_bar_edit, this);
I try to add a view dynamically with:
// create layout parameters
RelativeLayout.LayoutParams lparams = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.FILL_PARENT,
RelativeLayout.LayoutParams.WRAP_CONTENT);
lparams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
lparams.addRule(RelativeLayout.ALIGN_PARENT_TOP);
lparams.addRule(RelativeLayout.ABOVE, R.id.bottom_bar_buttons);
// RelativeLayout editMain = (RelativeLayout)
// findViewById(R.id.bottom_bar_edit);
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View noteBar = inflater.inflate(R.layout.lay_bottom_bar_notes, null);
this.addView(noteBar, lparams);
Any idea whats going wrong?
Thanks!

Related

Custom Relative layout not rendering any children

Intro:
I am attempting to add various Views to my custom RelativeLayout, i.e. Buttons, ImageViews, etc however none of them render/show.
Documentation:
As shown on numerous SO questions: here, here, here, here and many more,
I have the standard requirements for extending a layout, i.e. the 3 constructors, that being:
public RelativeLayout(Context context) {}
public RelativeLayout(Context context, AttributeSet attrs) {}
public RelativeLayout(Context context, AttributeSet attrs, int defStyleAttr){}
referred to here on Android Developer site.
Implementation:
My RelativeLayout named DiceRoller has the following implementation:
public class DiceRoller extends RelativeLayout {
private DieContainer dieContainer;
private Context mContext;
private int speed;
private Runnable moveDies;
private Handler handler;
private Timer timer;
public DiceRoller(Context context) {
super(context);
mContext = context;
init();
}
public DiceRoller(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
init();
}
public DiceRoller(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mContext = context;
init();
}
private void init() {
//source : https://stackoverflow.com/questions/28265286/custom-relative-layout-not-showing-child-views
setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
setGravity(Gravity.CENTER);
ImageView mainImage = new ImageView(mContext);
mainImage.setId(1994);
LayoutParams params = new LayoutParams(100, 100);
mainImage.setImageResource(R.drawable.die1);
mainImage.setLayoutParams(params);
addView(mainImage);
RelativeLayout.LayoutParams crossParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
crossParams.addRule(RelativeLayout.ALIGN_TOP | RelativeLayout.ALIGN_LEFT, mainImage.getId());
ImageView crossImage = new ImageView(mContext);
crossImage.setImageResource(R.drawable.die6);
crossImage.setLayoutParams(crossParams);
addView(crossImage);
TextView tv = new TextView(mContext);
tv.setText("hello world");
addView(tv);
}
}
Please Note: the contents of the init() method was purely to test if views were infact rendered. This was my last attempt at debugging the issue, previously I added views from my MainActivity aswell, obviously without success
With an associated layout file
<?xml version="1.0" encoding="utf-8"?>
<com.myapp.DiceRoller
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="1000px"
android:layout_height="1000px"
android:background="#color/colorAccent"
android:id="#+id/rollerBack">
</com.myapp.DiceRoller>
What is the problem:
The problem is simple. No child of the layout is rendered/shown/visible.
I attempted adding a child in my MainActivity, programmatically. It did not render. I attempted adding a child within this RelativeLayout class, it did not render.
Additional Info:
note: When adding views, I always added text or some image, I also set the X, Y values, also included RelativeLayout.LayoutParams() with the wrap option set.
When debugging this issue, if I added a view (ImageView, Button, etc), the layout has each child stored, and each child's parent is this RelativeLayout. Each child has a width, height, X, Y value and some content (either an image or text), thus the problem does not lie with the children.
I am at a loss, I have no idea why it doesn't render, any help would be greatly appreciated!

Inflating an xml vs. creating a new instance

Are these two the same?
A.
my_custom_view.xml
<?xml version="1.0" encoding="utf-8"?>
<com.abc.views.MyCustomView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
MyCustomView.java
public class MyCustomView extends LinearLayout {
public MyCustomView(Context context) {
super(context);
init();
}
public static MyCustomView inflate(ViewGroup parent) {
MyCustomView view = (MyCustomView) LayoutInflater.
from(parent.getContext()).inflate(R.layout.my_custom_view, parent, false);
return view;
}
B.
MyCustomView.java
public class MyCustomView extends LinearLayout {
public MyCustomView(Context context) {
super(context);
init();
}
public static MyCustomView inflate(ViewGroup parent) {
MyCustomView view = new MyCustomView(parent.getContext());
parent.addChild(view);
return view;
}
When we run,
MyCustomView.inflate(parent);
Not exactly. Long story short, the differences here is in instance A, the LayoutParams will be set to "MATCH_PARENT" for the width and "WRAP_CONTENT" for the height. In instance B, the LayoutParams will be whatever the default the parent View applies (usually WRAP_CONTENT for both width and height).
Additionally, in instance A, the view is not attached to the parent view. In instance B, the view is attached to the parent view.
Long story long, here's other differences.
public static MyCustomView inflate(ViewGroup parent) {
MyCustomView view = (MyCustomView) LayoutInflater.
from(parent.getContext()).inflate(R.layout.my_custom_view, parent, false);
return view;
}
This does a few things:
Inflates the view giving it layout parameters of the parent. If the
parent is a FrameLayout, then the LayoutParams instance will be a
FrameLayout.LayoutParams. If it is a LinearLayout, the
LayoutParams will be a LinearLayout.LayoutParams. The layout
parameters are assigned by the xml "layout_width" and
"layout_height". In this particular case, the width is set to MATCH_PARENT and the height is set to WRAP_CONTENT (although this can be overridden by the parent View).
The view is not added or attached to the parent view as shown by
the false parameter. (true will attach the view to the parent).
Any other attributes you eventually apply to the XML will be applied to the
View.
The alternate constructors will be applied so the different
attributes will be filled. Which constructor is called is dependent on which attributes you apply.
View#(Context context, AttributeSet attrs)
View#(Context context, AttributeSet attrs, int defStyleAttr)
View#(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)
On the other hand:
public static MyCustomView inflate(ViewGroup parent) {
MyCustomView view = new MyCustomView(parent.getContext());
parent.addChild(view);
return view;
}
Default LayoutParams will be applied to the child view. In most cases this is set to WRAP_CONTENT for both width and height, but it's up to the parent view to determine which.
The view is attached to the parent view. If the caller were to try to add it to another parent view, it would result in a crash.
Absolutely no additional attributes are applied to the View. They will have to be added manually.
Only the View#(Context context) constructor is used in creation.

Custom Views don't show up in Custom ViewGroup

I'm trying to create a card game for Android, and I'm stuck on a confusing Issue.
I have a Custom View called CardBG that extends from the ViewFlipper class, so that i can flip the card around and show the front and the back. this works fine.
But i need to add some other things to the Cards, like a Textfield for example. So i created a Viewgroup in the belief that i can simply add Views to it. Adding this ViewGroup to my Activity results in nothing though.
What am I doing wrong? Is this a wrong approach alltogether?
I've also tried having Card extend a layout-class, such as RelativeLayout, but it gives me the same result.
Here is the relevant code, adding the cards has to be done dynamically, so no xml shenanigans:
TestActivity.java
public class TestActivity extends Activity {
RelativeLayout menuLayout;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_menu);
menuLayout = (RelativeLayout) findViewById(R.id.layout_menu);
Card c = new Card(this, null);
c.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
menuLayout.addView(c);
}
}
Card.java
public class Card extends ViewGroup{
CardBG background;
TextView text1;
public Card(Context context, AttributeSet attrs) {
super(context, attrs);
Log.w("Card", "Constructor");
background = new CardBG(context, null);
background.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
this.addView(background);
}
(protected void onLayout is also in this file, but i do nothing in that method except calling super.onLayout)
}
CardBG.java
public class CardBG extends ViewFlipper{
ImageView blue;
ImageView red;
public CardBG(Context context, AttributeSet attrs) {
super(context, attrs);
Log.w("CardBG", "Constructor");
blue = new ImageView(context);
blue.setImageResource(R.drawable.card_blue);
blue.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
this.addView(blue);
red = new ImageView(context);
red.setImageResource(R.drawable.card_red);
red.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
this.addView(red);
//from here on out there are only onclick listener to test the flipping animations
}
While extending ViewGroup. You must have to implement onLayout method. In onLayout you need to call layout method on each child of this ViewGroup and provide desired position (relatively to parent) for them. You can check source code of FrameLayout (one of the simpliest subclasses of ViewGroup) to find out how it works.
Although, you may extend your view from RelativeLayout, LinearLayout or simple FrameLayout instead. RelativeLayout would give onLayout implementation by itself and provide relative positions to its children.
EDIT:
You might need to inflate layout in current view.
Sample Code:
public class Card extends RelativeLayout {
public Card(Context context, AttributeSet attr) {
super(context, attr);
View.inflate(context, R.layout.my_card_layout, this);
}
}

Use XML Layout as view for View Subclass?

I feel as though I used to know how to do this, but I'm currently drawing a blank. I have a class that extends from View (Card) and I wrote a layout for it in XML. What I want to do is set the View of Card to be the XML View in the constructor, so I can use the methods in Card to set TextViews and whatnot. Any suggestions? Code below:
Card.java:
(I have View.inflate(context, R.layout.card_layout, null); there as an example of what I want to do, but it's not working. I basically want the class to be the interface for the View, and in order to do that I need to somehow assign the XML layout to the View. Do I use something along the lines of setContentView(View view)? There is no such method in the View class, but is there something like it?)
public class Card extends View {
TextView tv;
public Card(Context context) {
super(context);
View.inflate(context, R.layout.card_layout, null);
tv = (TextView) findViewById(R.id.tv);
}
public Card(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
View.inflate(context, R.layout.card_layout, null);
tv = (TextView) findViewById(R.id.tv);
}
public Card(Context context, AttributeSet attrs) {
super(context, attrs);
View.inflate(context, R.layout.card_layout, null);
tv = (TextView) findViewById(R.id.tv);
}
public void setText(String text) {
tv.setText(text);
}
}
card_layout.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="336dp"
android:layout_height="280dp"
android:layout_gravity="center"
android:background="#drawable/card_bg"
android:orientation="vertical" >
<TextView
android:id="#+id/tv"
android:layout_height="fill_parent"
android:layout_width="wrap_content"
android:textSize="24dp"
/>
</LinearLayout>
What you're trying to do is not possible with the current setup. A View(or a direct subclass of it) represent a single view it doesn't have the notion of child views, what you're trying to do. The LayoutInflater can't be used with a simple View because the simple View class doesn't have the methods to actually add the child to it(like the addView() method).
On the other hand, the correct class to use to be able to have children is the ViewGroup(or one of the direct subclasses like LinearLayout, FrameLayout etc) which accept adding Views or other ViewGroups to it, by supplying the addView methods. In the end your class should be:
public class Card extends ViewGroup {
TextView tv;
public Card(Context context) {
super(context);
View.inflate(context, R.layout.card_layout, this);
tv = (TextView) findViewById(R.id.tv);
}
public Card(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
View.inflate(context, R.layout.card_layout, this);
tv = (TextView) findViewById(R.id.tv);
}
public Card(Context context, AttributeSet attrs) {
super(context, attrs);
View.inflate(context, R.layout.card_layout, this);
tv = (TextView) findViewById(R.id.tv);
}
public void setText(String text) {
tv.setText(text);
}
}
If I recall you have to override onLayout if you extend ViewGroup, so instead(and because of your layout file), you should look at extending LinearLayout and replace the LinearLayout from the xml layout with a merge tag.
You should be able to use your class name in the layout. Something like:
<your.package.name.Card
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="336dp"
android:layout_height="280dp"
...
Just call findViewById to get child views.
To use your Card class, you use the inflator to get an instance, then attach it to a parent view.
LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
Card card = (Card) inflater.inflate(R.layout.card_layout, null);
parentView.addView(card);
Have a look at the docs for more info.

How to set width and height for custom view in programmatically?

I have created a custom view named MyDraw ,this is my MyDraw code,
public class MyDraw extends View {
public MyDraw(Context context) {
super(context);
}
public MyDraw(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public MyDraw(Context context, AttributeSet attrs) {
super(context, attrs);
}
........................................
}
I have added the view in XML file using package name. It is working fine. Now I want to set height and width for the MyDraw in run time,for that i have used following code,
mMyDraw.setLayoutParams(new LayoutParams(220, 300));
but i got Exception like,
java.lang.ClassCastException: android.view.ViewGroup$LayoutParams
How to solve this exception?
please help me..
You must override the onMeasure() method of the View.
For a nice example you can check here: http://kahdev.wordpress.com/2008/09/13/making-a-custom-android-button-using-a-custom-view/
And a very cool video that I would recommend is here: http://marakana.com/forums/android/general/563.html
Hope this helps!
Override the onMeasure() method, have a look here
There is a simple way:
based on our custom view parent class we can use layout param.
for example if our custom view is extended from FrameLayout:
FrameLayout.LayoutParams params = (LayoutParams) findViewById(R.id.root).getLayoutParams();
params.width = newwidth;
params.height = newHeight;
setLayoutParams(params);
where "R.id.root" is id of our root view in custom_view.xml that in this case is FrameLayout.

Categories

Resources