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.
Related
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!
I'm having trouble understanding why my extended layout isn't working. I made a class which goes
public class MyLayout extends RelativeLayout {
public MyLayout(Context context) {
super(context);
}
}
I wrote the XML as
<package.MyLayout
. . .
</package.MyLayout>
The method where I get the error is in the activity where I have called setContentView(R.layout.layout_relative).
I don't understand what I'm doing wrong because surely you inflate in the activity from the XML layout which is building on the custom class where I can make my overrides?
you need the other constructor, the one that takes two parameters:
public MyLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
which is used when the layout is inflated from the layout
You have specified the wrong constructors!
Android xml inflation uses
public RelativeLayout (Context context, AttributeSet attrs, int
defStyleAttr)
public RelativeLayout (Context context, AttributeSet
attrs, int defStyleAttr, int defStyleRes) since api 21
does anybody know, how to get a referenced xml layout, programmatically (in code) for my custom widget. I have already created a custom declare-styleable, with my desired attributes and I know how to get ohter xml attribute values, like string or integers.
What I want to do is something like this:
<MyCustomView
xmlns:my="http://schemas.android.com/apk/res-auto"
id="#+id/view"
my:headerLayout="#layout/my_fancy_layout"
/>
So I want to retrieve my_fancy_layout programmatically and inflate that layout in the code of MyCustomView.
Any idea how to do that?
Edit: I guess I can retreive the resource id with
int resId = attrs.getAttributeResourceValue(androidns, "headerLayout", 0);
But whats the correct namespace if I MyCustomView is a library project and if I would like to use
xmlns:my="http://schemas.android.com/apk/res-auto"
Ok, i found the solution by myself:
you have to retrieve a TypedArray from yout AttributeSet.
than you can access your desired resource id with something like this:
TypedArray attrs = ... ;
int headerRes = attrs.getResourceId(R.styleable.MyCustomWidget_headerLayout, -1);
than you can inflate like usually:
LayoutInflater.from(context).inflate(headerRes, this);
You can indeed inflate your layout in the constructor of your custom view:
public class MyCustomView extends /* LinearLayout, RelativeLayout, etc. */ {
public MyCustomView(Context context, AttributeSet attrs) {
super(context, attrs);
initView(context, attrs);
}
public MyCustomView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initView(context, attrs);
}
protected void initView(Context context, attrs) {
LayoutInflater.from(context).inflate(attrs.getAttributeResourceValue("http://schemas.android.com/apk/res-auto", "headerLayout", 0), this, true);
}
}
I have a LinearLayout with some Views in it. Then I want to treat this element as a View, so I created a new class extending from LinearLayout. Now when I dynamically add a new instance of this class into the layout I see nothing. I believe I have to get the View somehow from my class, but don't know how. Is it possible to somehow assocciate this new class with an xml?
Update:
public class Task extends LinearLayout {
public Task(Context context) {
super(context);
LayoutInflater.from(context).inflate(R.layout.task_view, this, false);
}
public Task(Context context, AttributeSet attrs) {
super(context, attrs);
LayoutInflater.from(context).inflate(R.layout.task_view, this, false);
}
public Task(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
LayoutInflater.from(context).inflate(R.layout.task_view, this, false);
}
}
Then:
Task newTask = new Task(getActivity());
someLinearLayout.addView((View) newTask); // happens nothing
You can use different approaches like:
Inflating it into a View
Using <include> tag
Inflating:
public class InflatedView extends LinearLayout
{
public InflatedView(Context c)
{
super(c);
LayoutInflater.from(this).inflate(R.layout.your_other_layout, this);
}
//override other constructors too.
}
Now you can use this in your xmls like this:
<com.your.package.InflatedView android:layout_height="etc" other:attribute="here" />
Include:
Very simple, use include tag:
<include layout="#layout/your_other_layout"/>
Here are RomainGuy's layout tricks.
I have a custom view and I simply wish to access the xml layout value of layout_height.
I am presently getting that information and storing it during onMeasure, but that only happens when the view is first painted. My view is an XY plot and it needs to know its height as early as possible so it can start performing calculations.
The view is on the fourth page of a viewFlipper layout, so the user may not flip to it for a while, but when they do flip to it, I would like the view to already contain data, which requires that I have the height to make the calculations.
Thanks!!!
that work :)... you need to change "android" for "http://schemas.android.com/apk/res/android"
public CustomView(final Context context, AttributeSet attrs) {
super(context, attrs);
String height = attrs.getAttributeValue("http://schemas.android.com/apk/res/android", "layout_height");
//further logic of your choice..
}
You can use this:
public CustomView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
int[] systemAttrs = {android.R.attr.layout_height};
TypedArray a = context.obtainStyledAttributes(attrs, systemAttrs);
int height = a.getDimensionPixelSize(0, ViewGroup.LayoutParams.WRAP_CONTENT);
a.recycle();
}
From public View(Context context, AttributeSet attrs) constructor docs:
Constructor that is called when
inflating a view from XML. This is
called when a view is being
constructed from an XML file,
supplying attributes that were
specified in the XML file.
So to achieve what you need, provide a constructor to your custom view that takes Attributes as a parameter, i.e.:
public CustomView(final Context context, AttributeSet attrs) {
super(context, attrs);
String height = attrs.getAttributeValue("android", "layout_height");
//further logic of your choice..
}
• Kotlin Version
The answers which are written to this question do not completely cover the issue. Actually, they are completing each other. To sum up the answer, first we should check the getAttributeValue returning value, then if the layout_height defined as dimension values, retrieve it using getDimensionPixelSize:
val layoutHeight = attrs?.getAttributeValue("http://schemas.android.com/apk/res/android", "layout_height")
var height = 0
when {
layoutHeight.equals(ViewGroup.LayoutParams.MATCH_PARENT.toString()) ->
height = ViewGroup.LayoutParams.MATCH_PARENT
layoutHeight.equals(ViewGroup.LayoutParams.WRAP_CONTENT.toString()) ->
height = ViewGroup.LayoutParams.WRAP_CONTENT
else -> context.obtainStyledAttributes(attrs, intArrayOf(android.R.attr.layout_height)).apply {
height = getDimensionPixelSize(0, ViewGroup.LayoutParams.WRAP_CONTENT)
recycle()
}
}
// Further to do something with `height`:
when (height) {
ViewGroup.LayoutParams.MATCH_PARENT -> {
// defined as `MATCH_PARENT`
}
ViewGroup.LayoutParams.WRAP_CONTENT -> {
// defined as `WRAP_CONTENT`
}
in 0 until Int.MAX_VALUE -> {
// defined as dimension values (here in pixels)
}
}