I'm getting a null pointer exception in my custom view (which is derived from a LinearLayout) because it can't find its child views. Here is the code:
public class MyView extends LinearLayout
{
public MyView(Context context, AttributeSet attrs)
{
this(context, attrs, 0);
}
public MyView(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
}
private TextView mText;
#Override
protected void onFinishInflate()
{
super.onFinishInflate();
mText = (TextView) findViewById(R.id.text);
if (isInEditMode())
{
mText.setText("Some example text.");
}
}
}
Here is the layout (my_view.xml):
<?xml version="1.0" encoding="utf-8"?>
<com.example.views.MyView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<TextView
android:id="#+id/text"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:ellipsize="end"
android:maxLines="4"
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:text="Some text" />
</com.example.views.MyView>
And here is how I put it in the XML file:
<com.example.views.MyView
android:id="#+id/my_view"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
But when I try to preview it in the layout editor I get an NPE on mText.setText(...) because getViewById() returns null.
What's going on?
Clarification
The reason I expect this to work, is if I do
MyView v = (MyView)inflater.inflate(R.layout.my_view);
((TextView)v.findViewById(R.id.text)).setText("Foo");
everything works fine. Is that not what the layout inflater does when it goes through a layout file? In any case, how can I handle both situations correctly (without getting pointless nested views)?
In you XML file you are trying to use a custom view class (com.example.views.MyView) and in the same time trying to add a TextView inside. It's not possible.
Here is what you need to change:
You must inflate XML file in the code:
public MyView(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
LayoutInflater.from(context).inflate(R.layout.<your_layout>.xml, this);
}
And modify the XML layout file like this:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<TextView
android:id="#+id/text"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:ellipsize="end"
android:maxLines="4"
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:text="Some text" />
</LinearLayout>
Related
I have an activity loaded from XML, with views having IDs as usual:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="80dp"
android:layout_height="110dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<FrameLayout
android:layout_width="70dp"
android:layout_height="70dp"
android:layout_gravity="center_horizontal"
android:background="#drawable/white_circle">
<com.myapp.views.CircleImageView
android:id="#+id/imageView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="16dp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="-12dp"
android:background="#drawable/price_background">
<TextView
android:id="#+id/priceView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginLeft="4dp"
android:layout_marginRight="4dp"
android:text="0.1 BTC"
android:textAllCaps="true"
android:textColor="#color/white"
android:textSize="10sp"
android:textStyle="bold" />
</FrameLayout>
<TextView
android:id="#+id/nameView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:gravity="center_horizontal"
android:lineSpacingMultiplier="0.8"
android:lines="2"
android:text="Bacon Cheeseburger"
android:textSize="10sp" />
</LinearLayout>
</FrameLayout>
I'm trying to reference three views in code:
public ItemViewHolder(View itemView) {
super(itemView);
nameView = itemView.findViewById(R.id.nameView);
priceView = itemView.findViewById(R.id.priceView);
imageView = itemView.findViewById(R.id.imageView);
}
nameView and priceView are referenced correctly, however, imageView isn't being referenced and is null:
Why can't I reference imageView?
(If I traverse the view tree, it is there.)
UPDATE: I did both Clean Project and Invalidate Caches/Restart, the problem persists.
UPDATE 2: ItemViewHolder is derived from RecyclerView.ViewHolder. CircleImageView is derived from FrameLayout (not ImageView). This XML is the layout of my view holder.
UPDATE 3: Here is my circle view's constructor:
public class CircleImageView extends FrameLayout {
public CircleImageView(Context context) {
super(context);
init();
}
public CircleImageView(Context context, AttributeSet attrs) {
super(context);
init();
}
public CircleImageView(#NonNull Context context, #Nullable AttributeSet attrs, #AttrRes int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
...
}
Also, as Subzero noted, I've checked the ID property (mID field) of the view, and it's -1, which seems to be the cause of the problem. I have no idea why it is -1 though.
Change the super call in your two-parameter constructor to:
super(context, attrs);
When a View is inflated from a layout, the XML attributes and their values are passed into the two-parameter constructor via the AttributeSet. If you don't pass that to the superclass, the id you've specified in the XML is never set on the View, so findViewById() won't find it with the given ID.
I like Use this as follows, hope it is helpful.
public class CircleImageView extends FrameLayout {
public CircleImageView(Context context) {
this(context,null);
}
public CircleImageView(Context context, AttributeSet attrs) {
this(context.attrs,0);
}
public CircleImageView(#NonNull Context context, #Nullable AttributeSet attrs, #AttrRes int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
...
}
I think the problem is, that your imageView in layout.xml is a custom view (com.myapp.views.CircleImageView), not a regular android ImageView.
Try cast to ImageView, if the class extends imageview
ImageView iv = (ImageView) itemView.findViewById(R.id.imageView));
or use it as your custom view
CircleImageView iv = (CircleImageView) itemView.findViewById(R.id.imageView));
I'm making some grid with image and text, using GridLayoutManager. But currently my items have different height if on one row text is on one line and on the second row text has two lines, which don't looks good. How to make all items equals to each other (best option if every item height will be equal to max element height
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="#color/white"
android:layout_margin="1dp">
<ImageView
android:id="#+id/image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"/>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:textAlignment="center"
tools:text="Long title long title long title(560)" />
</RelativeLayout>
</LinearLayout>
Try below code may work for you, where I have created custom relative layout
package com.test;
public class MySquareRelativeLayout extends RelativeLayout {
public MySquareRelativeLayout(Context context) {
super(context);
}
public MySquareRelativeLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MySquareRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#TargetApi(VERSION_CODES.LOLLIPOP)
public MySquareRelativeLayout(Context context, AttributeSet attrs,int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// Set a square layout.
super.onMeasure(widthMeasureSpec, widthMeasureSpec);
}
}
<?xml version="1.0" encoding="utf-8"?>
<com.test.MySquareRelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/elementRootView"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:id="#+id/image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"/>
<TextView
android:id="#+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/image"
android:textAlignment="center"
tools:text="Long title long title long title(560)" />
</com.test.MySquareRelativeLayout>
I have an activity loaded from XML, with views having IDs as usual:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="80dp"
android:layout_height="110dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<FrameLayout
android:layout_width="70dp"
android:layout_height="70dp"
android:layout_gravity="center_horizontal"
android:background="#drawable/white_circle">
<com.myapp.views.CircleImageView
android:id="#+id/imageView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="16dp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="-12dp"
android:background="#drawable/price_background">
<TextView
android:id="#+id/priceView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginLeft="4dp"
android:layout_marginRight="4dp"
android:text="0.1 BTC"
android:textAllCaps="true"
android:textColor="#color/white"
android:textSize="10sp"
android:textStyle="bold" />
</FrameLayout>
<TextView
android:id="#+id/nameView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:gravity="center_horizontal"
android:lineSpacingMultiplier="0.8"
android:lines="2"
android:text="Bacon Cheeseburger"
android:textSize="10sp" />
</LinearLayout>
</FrameLayout>
I'm trying to reference three views in code:
public ItemViewHolder(View itemView) {
super(itemView);
nameView = itemView.findViewById(R.id.nameView);
priceView = itemView.findViewById(R.id.priceView);
imageView = itemView.findViewById(R.id.imageView);
}
nameView and priceView are referenced correctly, however, imageView isn't being referenced and is null:
Why can't I reference imageView?
(If I traverse the view tree, it is there.)
UPDATE: I did both Clean Project and Invalidate Caches/Restart, the problem persists.
UPDATE 2: ItemViewHolder is derived from RecyclerView.ViewHolder. CircleImageView is derived from FrameLayout (not ImageView). This XML is the layout of my view holder.
UPDATE 3: Here is my circle view's constructor:
public class CircleImageView extends FrameLayout {
public CircleImageView(Context context) {
super(context);
init();
}
public CircleImageView(Context context, AttributeSet attrs) {
super(context);
init();
}
public CircleImageView(#NonNull Context context, #Nullable AttributeSet attrs, #AttrRes int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
...
}
Also, as Subzero noted, I've checked the ID property (mID field) of the view, and it's -1, which seems to be the cause of the problem. I have no idea why it is -1 though.
Change the super call in your two-parameter constructor to:
super(context, attrs);
When a View is inflated from a layout, the XML attributes and their values are passed into the two-parameter constructor via the AttributeSet. If you don't pass that to the superclass, the id you've specified in the XML is never set on the View, so findViewById() won't find it with the given ID.
I like Use this as follows, hope it is helpful.
public class CircleImageView extends FrameLayout {
public CircleImageView(Context context) {
this(context,null);
}
public CircleImageView(Context context, AttributeSet attrs) {
this(context.attrs,0);
}
public CircleImageView(#NonNull Context context, #Nullable AttributeSet attrs, #AttrRes int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
...
}
I think the problem is, that your imageView in layout.xml is a custom view (com.myapp.views.CircleImageView), not a regular android ImageView.
Try cast to ImageView, if the class extends imageview
ImageView iv = (ImageView) itemView.findViewById(R.id.imageView));
or use it as your custom view
CircleImageView iv = (CircleImageView) itemView.findViewById(R.id.imageView));
This question already has answers here:
Android EditText view Floating Hint in Material Design
(10 answers)
Closed 5 years ago.
I am trying to make custom EditText Something look like this.
Currently i am using Custom View Inheriting from ConstraintLayout
DefaultEditTextContainerView.java
public class DefaultEditTextContainerView extends ConstraintLayout
{
#BindView(R.id.titleText)
public TextView titleText;
#BindView(R.id.contentEditText)
public EditText contentEditText;
private String mTitleText;
private String mHintText;
public DefaultEditTextContainerView(Context context) {
super(context);
init(null, 0);
}
public DefaultEditTextContainerView(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs, 0);
}
public DefaultEditTextContainerView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(attrs, defStyleAttr);
}
private void init(AttributeSet attrs, int defStyle) {
View view = inflate(getContext(), R.layout.view_default_edit_text_container_view,
this);
ButterKnife.bind(this, view);
//region Load attributes
final TypedArray typedArray = getContext().obtainStyledAttributes(
attrs, R.styleable.DefaultEditTextContainerView, defStyle, 0);
if (typedArray.hasValue(R.styleable.DefaultEditTextContainerView_titleText)) {
mTitleText = typedArray.getString(
R.styleable.LandingPageSectionItemView_titleText);
}
if (typedArray.hasValue(R.styleable.DefaultEditTextContainerView_hintText)) {
mHintText = typedArray.getString(
R.styleable.DefaultEditTextContainerView_hintText);
}
typedArray.recycle();
// endregion
titleText.setText(mTitleText);
contentEditText.setHint(mHintText);
}
}
view_default_edit_text_container_view.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:maxHeight="100dp">
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginBottom="24dp"
android:background="#color/colorLight"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/linearLayout10"/>
<TextView
android:id="#+id/titleText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="필드 이름"
android:textColor="#color/textLightDark"
android:textSize="12sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<LinearLayout
android:id="#+id/linearLayout10"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:gravity="center_vertical"
android:orientation="horizontal"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/titleText">
<EditText
android:id="#+id/contentEditText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="#android:color/transparent"
android:ems="10"
android:hint="예) 힌트 텍스트"
android:inputType="text"
android:padding="10dp"
android:singleLine="true"
android:textColor="#color/textLightDark"
android:textColorHint="#color/colorLight"
android:textSize="18sp"
tools:layout_editor_absoluteX="99dp"
tools:layout_editor_absoluteY="271dp"/>
</LinearLayout>
</android.support.constraint.ConstraintLayout>
But the problem is, I have to access more than 5 attributes that are assigned to EditText. So i thought my CustomView Should Inherit from EditText. And that's what i am trying to do...
how can i inherit from EditText And create the same looking view as above?
OR
how can i Access all EditText Attributes from xml not specifing and overriding attributes via attr.xml ...
thank you!
===Edit==
what i want
ParentView(ConstraintLayout)
- ViewA(TextView)
- ViewB(EditText)
want to make a view looks like that but inherit from ViewB(EditText)
so i can mainly access to EditText's attributes
From your mockup which shows the desired result,you might like this library to achieve this easily:https://github.com/HITGIF/TextFieldBoxes.I have used this library before and it is pretty easy to implement.
Here is the preview of the output the library gives:
I'm having some trouble when I extend a LinearLayout.
The onClick event is never fired.
My code:
public class Tab extends LinearLayout {
public Tab(Context context) {
super(context);
init(context);
}
public Tab(Context context, AttributeSet attrs) {
super(context, attrs);
// ... get attrs ...
init(context);
}
public Tab(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}
public void init(Context context) {
inflate(context, R.layout.tab, this);
// ... some layout tasks ...
iconView.requestLayout();
}
}
Layout tab.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/rootView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center_horizontal|center_vertical"
android:background="#drawable/bg_tab"
android:clickable="true"
android:duplicateParentState="true">
<ImageView
android:id="#+id/icon"
android:layout_width="0dp"
android:layout_height="0dp"
android:adjustViewBounds="true"
android:scaleType="centerInside"
android:layout_gravity="center_horizontal|center_vertical"
android:clickable="false"
android:duplicateParentState="true"/>
<TextView
android:id="#+id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="false"
android:gravity="center_horizontal"
android:layout_gravity="center_horizontal|center_vertical"
android:textAllCaps="true"
android:textColor="#drawable/tab_text_color"
android:textSize="11sp"
android:duplicateParentState="true"/>
</LinearLayout>
If I put a eventListener on a Tab's child view, it works, but when attached to the Tab itself is doesn't.
Can someone see where my mistake is?
I just set android:clickable to false on rootView and works! =)