i make a custom LinearLayout, xml error has occurred
this code is xamarin(C#) code, but xml code is like a Java. write the code.
Android.Views.InflateException: Binary XML file line #1: Error inflating class com.eappandroid.phone1.OpendCheckLinearLayout
first, Unhandled Exception line is (in LeftDrawerMenuItemAdapter class)(in GetView)
convertView = ((Activity)Context).LayoutInflater.Inflate(Resource.Layout.LeftDrawerMenu_List_Item, null);
LeftDrawerMenu_List_Item xml
<?xml version="1.0" encoding="utf-8"?>
<com.eappandroid.phone1.OpendCheckLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="52dp"
android:background="#drawable/menu_item_background_color_pressed"
android:minHeight="25px"
android:minWidth="25px"
android:id="#+id/left_drawer_list_item_layout"
android:orientation="horizontal">
<ImageView
android:id="#+id/left_drawer_list_icon"
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_gravity="center"
android:layout_marginLeft="12dp"
android:gravity="center" />
<TextView
android:id="#+id/left_drawer_list_item_text"
android:layout_width="wrap_content"
android:layout_height="52dp"
android:gravity="left|center"
android:layout_gravity="center"
android:layout_marginLeft="8dp"
android:layout_weight="1"
android:text="item"
android:textColor="#drawable/menu_item_title_color_pressed"
android:textSize="16sp"
android:textStyle="bold" />
<ImageView
android:id="#+id/left_drawer_noti_alert"
android:layout_width="22dp"
android:layout_height="22dp"
android:layout_gravity="center"
android:layout_marginRight="18dp"
android:background="#drawable/menu_icon_noti_new_alert"
android:gravity="center" />
</com.eappandroid.phone1.OpendCheckLinearLayout>
OpendCheckLinearLayout class
namespace EAppAndroid.Protype.LeftDrawerMenu2
{
public class OpendCheckLinearLayout : LinearLayout
{
private static readonly int[] STATE_MENU_OPEND = { Resource.Attribute.state_menu_opend };
public bool menuOpen = false;
public OpendCheckLinearLayout(Context context)
: base(context, null)
{
}
public OpendCheckLinearLayout(Context context, Android.Util.IAttributeSet attributeSet)
: base(context, attributeSet)
{
}
public OpendCheckLinearLayout(Context context, Android.Util.IAttributeSet attributeSet, int defStyle)
: base(context, attributeSet, defStyle)
{
}
protected override int[] OnCreateDrawableState(int extraSpace)
{
if (menuOpen)
{
int[] drawableStates = base.OnCreateDrawableState(extraSpace + 1);
MergeDrawableStates(drawableStates, STATE_MENU_OPEND);
return drawableStates;
}
else
{
return base.OnCreateDrawableState(extraSpace);
}
}
public void setMenuOpen(bool menuOpen)
{
if (this.menuOpen != menuOpen)
{
this.menuOpen = menuOpen;
}
}
}
}
Thanks for the help
Your namespace seems to be wrong.
You put com.eappandroid.phone1.OpendCheckLinearLayout in your xml, but in your OpendCheckLinearLayout class you have EAppAndroid.Protype.LeftDrawerMenu2, so you should probably put com.eappandroid.Protype.LeftDrawerMenu2.OpendCheckLinearLayout
EDIT:
Seems that only the namespace is required in the xml, so you should put eappandroid.Protype.LeftDrawerMenu2.OpendCheckLinearLayout
Actually, the inflate exception is not actually the problem, but it really comes from another deeper issue in your layout that is then wrapped in an InflateException. A common issue is an out of memory exception when trying to inflate an ImageView loading a drawable resource. If one of this resources has a high pixel resolution it would take a lot of memory causing then an inflate exception.
So basically, verify that the pixel resolution in your drawables images are just the minimum necessary for your layout. It helped me many times.
I hope it'll work for you too.
Related
I use this kind of ViewGroup:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="#+id/icon"
android:layout_width="16dp"
android:layout_height="16dp"
android:src="#drawable/icon1"/>
<TextView
android:id="#+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/text1"/>
<TextView
android:id="#+id/data"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
I must use 2 such layouts In my fragment, but with different icon and title. Is there some way to implement it without copy/paste and RecyclerView?
There are several ways to deal with it.
1. Use the include tag.
1.1. Move LinearLayout to a separate file.
1.2 Add layout using the include tag two times with different ids:
<LinearLayout ...>
<include layout="#layout/your_layout" android:id="#+id/first" />
<include layout="#layout/your_layout" android:id="#+id/second" />
</LinearLayout>
1.3 Set content programmatically:
View first = findViewById(R.id.first);
first.findViewById(R.id.date).setText("05/05/2020");
View second = findViewById(R.id.second);
second.findViewById(R.id.date).setText("04/04/2020");
2. Implement a custom view.
There are two ways also. The first is to inflate layout inside FrameLayout. The second is to extend LinearLayout and add content programmatically. I'll show you the first one.
public class YourCustomView extends FrameLayout {
public MyView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
inflate(context, R.layout.your_custom_view_layout, this);
}
public MyView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MyView(Context context) {
this(context, null);
}
public void setContent(int iconRes, int titleRes, String data) {
findViewById(R.id.icon).setDrawableRes(iconRes);
findViewById(R.id.title).setDrawableRes(titleRes);
findViewById(R.id.data).setText(data);
}
}
3. Just copy-paste it :)
As I see icon and title are static and only data content changes, so it is not worth it to reuse such a simple layout, IMO.
I've got a custom view for my app named AvatarView:
<?xml version="1.0" encoding="utf-8"?>
<com.ulouder.views.AdvancedRelativeLayout android:layout_width="wrap_content"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_gravity="center_horizontal"
android:layout_margin="0dp"
android:padding="0dp"
xmlns:android="http://schemas.android.com/apk/res/android">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="CP"
android:id="#+id/initialsView"
android:layout_alignTop="#+id/avatarView"
android:layout_alignLeft="#+id/avatarView"
android:layout_alignBottom="#+id/avatarView"
android:layout_alignRight="#+id/avatarView"
android:background="#drawable/avatar_background"
android:textColor="#color/white"
android:gravity="center"
android:textStyle="bold"
android:textSize="8sp" />
<com.makeramen.roundedimageview.RoundedImageView
app:riv_corner_radius="20dp"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/avatarView"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_marginTop="4dp"
android:layout_marginLeft="4dp"
android:layout_marginBottom="4dp"
app:riv_border_color="#color/lightGray"
app:riv_border_width="0.2dp" />
</com.uLouder.views.AdvancedRelativeLayout>
AdvancedRelativeLayout is just a superclass of RelativeLayout with a small fix, nothing special there. Then, I've created a view that uses my custom view:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<com.ulouder.views.AvatarView
android:layout_width="50dp"
android:layout_height="50dp"/>
</LinearLayout>
Nothing fancy either. But in the designer view of the second layout XML, I'm getting this:
The editor displays my view hierarchy like it has a nested instance of itself, while clearly there isn't. If I delete either one, they both get deleted. If I declare attributes on one of them, other also gets it. They are clearly the same instance. The only exception is setting an ID. Then the problem disappears, and only single instance is displayed as expected.
I've rebuilt the project, restarted Android Studio, but it's still the same. What am I doing wrong?
UPDATE: Nope, now, after editing id, the problem still continues again.
UPDATE 2: It's not just a layout so I can't use <include> tag. It's a custom view which has custom logic inside.
UPDATE 3: Here is my custom view's (relevant) code:
public class AvatarView extends FrameLayout {
public AvatarView(Context context) {
super(context);
init();
}
TextView initialsView;
RoundedImageView imageView;
public AvatarView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
void init(){
inflate(getContext(), R.layout.view_avatar, this);
initialsView = (TextView) findViewById(R.id.innerInitialsView);
imageView = (RoundedImageView) findViewById(R.id.innerImageView);
}
#SuppressWarnings("SuspiciousNameCombination")
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, widthMeasureSpec); //always square
imageView.setCornerRadius(widthMeasureSpec / 2f);
initialsView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, widthMeasureSpec * 30f);
}
}
UPDATE 4: It appears that this happens wherever I put my custom AvatarView class, not just at one place.
I did not find any reason to inflate the same view inside your class constructor method after checking the custom views documentation. Try to remove the inflate inside your init method.
...
public AvatarView(Context context) {
super(context);
init();
}
...
public AvatarView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
void init(){
// inflate(getContext(), R.layout.view_avatar, this);
initialsView = (TextView) findViewById(R.id.innerInitialsView);
imageView = (RoundedImageView) findViewById(R.id.innerImageView);
}
...
Sorry if this redundant with the ton of questions/answers on inflate, but I could not get a solution to my problem.
I have a compound view (LinearLayout) that has a fixed part defined in XML and additional functionalities in code. I want to dynamically add views to it.
Here is the XML part (compound.xml):
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/compoundView"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<TextView android:id="#+id/myTextView"
android:layout_width="110dp"
android:layout_height="wrap_content"
android:text="000" />
</LinearLayout>
I have defined in code a LinearLayout to refer to the XML:
public class CompoundControlClass extends LinearLayout {
public CompoundControlClass (Context context) {
super(context);
LayoutInflater li;
li = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
li.inflate(R.layout.compound_xml,*ROOT*, *ATTACH*);
}
public void addAView(){
Button dynBut = new Button();
// buttoin def+layout info stripped for brevity
addView(dynBut);
}
}
I tried to programmatically add a view with addAView.
If ROOT is null and ATTACH is false, I have the following hierarchy (per HierarchyViewer):
CompoundControlClass>dynBut
The original TextView in the XML is gone.
If ROOT is this and ATTACH is true, I have the following hierarchy:
CompoundControlClass>compoundView>myTextView
CompoundControlClass>dynBut
I would like to have
CompoundControlClass>myTextView
CompoundControlClass>dynBut
where basically the code and XML are only one unique View.
What have I grossly missed?
ANSWER BASED on feedback from D Yao ----------------------
The trick is to INCLUDE the compound component in the main layout instead of referencing it directly.
activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="#layout/comound"
android:id="#+id/compoundView"
android:layout_alignParentBottom="true"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
</RelativeLayout>
mainActivity.java
public class MainActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
CompoundControlClass c = (CompoundControlClass) this.findViewById(R.id.compoundView);
c.addAView(this);
}
}
CompoundControlClass.java
public class CompoundControlClass extends LinearLayout {
public CompoundControlClass(Context context) {
super(context);
}
public CompoundControlClass(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CompoundControlClass(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public void addAView(Context context){
ImageView iv = new ImageView(context);
iv.setImageResource(R.drawable.airhorn);
addView(iv);
}
}
compound.xml
<com.sounddisplaymodule.CompoundControlClass xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/compoundView"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<TextView
android:layout_width="110dp"
android:layout_height="wrap_content"
android:gravity="right"
android:textSize="40sp"
android:textStyle="bold"
android:text="0:00" />
</com.sounddisplaymodule.CompoundControlClass>
Why not just call addView on the linearlayout? I don't see the need for CompoundControlClass based on the needs you have listed.
LinearLayout v = (LinearLayout)findViewById(R.id.compoundView);
v.addView(dynBut);
In this case, v will contain myTextView, then dynBut.
if you wish to have other functions added and thus really feel a need for creating the compound control class, just leave the constructor as super(etc) and remove the rest
Then your xml would look like this:
<com.yourpackage.CompoundControlClass xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/compoundView"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<TextView android:id="#+id/myTextView"
android:layout_width="110dp"
android:layout_height="wrap_content"
android:text="000" />
</com.yourpackage.CompoundControlClass>
you will also have to ensure your CompoundControlClass.java contains the appropriate Constructor which takes both a Context and an attribute set.
Then, in your java, after you've called setContentView, you can do the following:
CompoundControlClass c = (CompoundControlClass)findViewById(R.id.compoundView);
Button b = new Button(context);
//setup b here or inflate your button with inflater
c.addView(b);
this would give you your desired heirarchy.
The documentation about this is really confusing. I simply need to add rectangels to a View I defined in my main.xml layout file. It will be a small part of the layout.
What I want to achieve is, I want to add shelves to a room but since the room shape and shelves change, I need to add them programmatically.
Below is a little part of my main.xml file, you can see the View I defined:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
android:id="#+id/relativeLayout2"
android:layout_width="600dp"
android:layout_height="650dp"
android:layout_marginTop="70dp"
android:layout_marginLeft="30dp"
android:layout_toRightOf="#+id/relativeLayout1" >
<TextView
android:id="#+id/textView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:text="#string/getDirections"
android:textSize="20dp"
android:textStyle="bold" />
<View
android:id="#+id/roomplan"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/textView3"
android:layout_marginTop="40dp"
android:background="#android:color/white" />
</RelativeLayout>
This is the custom View class I created to handle dynamic changes:
public class CustomView extends View {
ShapeDrawable roomFrame;
ArrayList<ShapeDrawable> shelfFrames;
public CustomView(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
#Override
protected void onDraw(Canvas canvas){
super.onDraw(canvas);
roomFrame.draw(canvas);
for (ShapeDrawable shelfFrame : shelfFrames){
shelfFrame.draw(canvas);
}
}
public void setRoom(Stage stage){
roomFrame = new ShapeDrawable(new RectShape());
roomFrame.getPaint().setColor(0xff74AC23);
roomFrame.setBounds(10, 10, stage.getWidth(), stage.getHeight());
}
public void setShelves(ArrayList<Shelf> shelves){
shelfFrames = new ArrayList<ShapeDrawable>();
for(int i = 0; i<shelves.size(); i++){
ShapeDrawable shelfFrame = new ShapeDrawable(new RectShape());
shelfFrame.getPaint().setColor(0xff74AC23);
shelfFrame.setBounds(shelves.get(i).getXPosition(), shelves.get(i).getYPosition(), shelves.get(i).getWidth(), shelves.get(i).getHeight());
shelfFrames.add(shelfFrame);
}
}
}
Now simply, when a new room plan is asked I am trying to assign this class to the View object in the xml layout:
public void loadRoomPlan(Room room, ArrayList<Shelf> shelves){
CustomView asdsView = (CustomView)findViewById(R.id.roomplan);
asdsView.setRoom(room);
asdsView.setShelves(shelves);
asdsView.invalidate();
}
I always get
Caused by: java.lang.ClassCastException: android.view.View cannot be cast to org.example.myproject.CustomView
error.
Probably I am doing this very very wrong, am I not?
The error seems to be in this line:
CustomView asdsView = (CustomView)findViewById(R.id.shopplan);
What is shopplan? In case it is a mistake and you meant R.id.roomplan try to subtitute the View in your layout for your Custom view:
<org.example.myproject.CustomView
android:id="#+id/roomplan"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/textView3"
android:layout_marginTop="40dp"
android:background="#android:color/white" />
UPDATE:
Try adding the other two constructors to your CustomView class:
public CustomView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
When you use a custom view in an xml layout, your view has to deal with the layout attributes (the constructor AttributeSet param).
I would like some of my preferences to have icons, like the Settings app.
I guess one way of doing this would be to copy all the relevant code and resources from the Settings app, but it seems like overkill for a couple of icons.
Also I don't like the idea of having to duplicate the code and resources in each project that requires settings icons.
Has anyone solved this already with a simpler or resource-free approach?
The Settings application uses a private custom PreferenceScreen subclass to have the icon -- IconPreferenceScreen. It is 51 lines of code, including the comments, though it also requires some custom attributes. The simplest option is to clone all of that into your project, even though you do not like that.
source code
Since API level 11 you can add icon to preferences:
http://developer.android.com/reference/android/preference/Preference.html#setIcon%28int%29
http://developer.android.com/reference/android/preference/Preference.html#attr_android:icon
For older Android versions, you have to use custom layouts and bind images in code, as #roger-l suggests.
Updated.... answered and working
Use a custom layout for the icon preference
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+android:id/widget_frame"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
android:gravity="center_vertical"
android:paddingRight="?android:attr/scrollbarSize">
<ImageView
android:id="#+id/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="6dip"
android:layout_marginRight="6dip"
android:layout_gravity="center" />
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="2dip"
android:layout_marginRight="6dip"
android:layout_marginTop="6dip"
android:layout_marginBottom="6dip"
android:layout_weight="1">
<TextView android:id="#+android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceLarge"
android:ellipsize="marquee"
android:fadingEdge="horizontal" />
<TextView android:id="#+android:id/summary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#android:id/title"
android:layout_alignLeft="#android:id/title"
android:textAppearance="?android:attr/textAppearanceSmall"
android:maxLines="2" />
</RelativeLayout>
</LinearLayout>
and the imported class for IconPreferenceScreen
public class IconPreferenceScreen extends Preference {
private final Drawable mIcon;
private static String mType;
public IconPreferenceScreen(Context context, AttributeSet attrs, int iconRes) {
this(context, attrs, 0, iconRes);
}
public IconPreferenceScreen(Context context, AttributeSet attrs,
int defStyle, int iconRes) {
super(context, attrs, defStyle);
setLayoutResource(R.layout.preference_icon);
mIcon = context.getResources().getDrawable(iconRes);
}
public IconPreferenceScreen(Context context, int iconRes) {
this(context, null, iconRes);
}
#Override
public void onBindView(View view) {
super.onBindView(view);
ImageView imageView = (ImageView) view.findViewById(R.id.icon);
if (imageView != null && mIcon != null) {
imageView.setImageDrawable(mIcon);
}
}
}
then you can just use a new IconPreferenceScreen in place of a Preference, and add an icon
Android 3.x Honeycomb shows icons defined in standard Preferences.
So probably the use of icon depends on Android OS version or screen size.