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:
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 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 have CustomLayout which has TextView on which I am setting text and drawable programmatically however the problem is when I set the drawable it is adding a huge padding with what I want is drawable to be more at the center rather than at the top.
Custom ViewGroup
public class ProfileGridView extends FrameLayout {
public ProfileGridView(#NonNull Context context) {
super(context);
initView(context,null);
}
public ProfileGridView(#NonNull Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
initView(context,attrs);
}
public ProfileGridView(#NonNull Context context, #Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView(context,attrs);
}
#TargetApi(21)
public ProfileGridView(#NonNull Context context, #Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
initView(context,attrs);
}
public void initView(Context context, AttributeSet attrs) {
TextView gridTextView;
View view = inflate(context, R.layout.square_grid, null);
gridTextView = (TextView) view.findViewById(R.id.grid_description);
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.ProfileGridView);
Drawable drawable = array.getDrawable(R.styleable.ProfileGridView_drawble);
String description = array.getString(R.styleable.ProfileGridView_grid_description);
gridTextView.setText(description);
gridTextView.setCompoundDrawablesWithIntrinsicBounds(null, drawable, null, null);
addView(view);
array.recycle();
}
}
CustomView LayoutFile
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/grid_description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawablePadding="8dp"
android:gravity="center"
android:padding="0dp"
android:textSize="20sp" />
MainActivit.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.example.views.ProfileGridView
android:layout_width="200dp"
android:layout_height="200dp"
app:drawble="#drawable/ic_message"
app:grid_description="Message"/>
</RelativeLayout>
Can you use a CustomView LayoutFile like this?
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center">
<ImageView
android:id="#+id/image"
android:layout_width="52dp"
android:layout_height="52dp" />
<TextView
android:id="#+id/grid_description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="4dp"
android:textSize="20sp"/>
</LinearLayout>
And set the drawable like this
ImageView image;
image = (ImageView) view.findViewById(R.id.image);
image.setImageDrawable(drawable);
Instead of
gridTextView.setCompoundDrawablesWithIntrinsicBounds(null, drawable, null, null);
EDIT
As you ask, you can make ProfileGridView wrap_content instead of 200dp. With setCompoundDrawablesWithIntrinsicBounds you attach the drawable to the bounds of the TextView (200dp). [You can check the documentation for more info](https://developer.android.com/reference/android/widget/TextView.html#setCompoundDrawablesWithIntrinsicBounds(android.graphics.drawable.Drawable, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable))
That's not a padding problem, is because you are setting the drawable width and height as 200dp
Can you use "wrap_content" in the drawable file?
If not just have a image file and set it as a drawable of the TextView
Setting the drawableBottom to an equally sized image will recenter the text. Here is a simple drawable that would do the trick:
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<size android:width="24dp"
android:height="24dp"/>
</shape>
I am trying to implement horizontal timeline. SO I have written the code to design the horizontal line but I am able to figure out how I will write text on the above and below of the line.
One more thing I don't want to use any other library.
I have try to solve it through Custom view as people here have been suggested but got struck.
timeline_segment.xml
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<LinearLayout
android:weightSum="1"
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:padding="3dp"
android:textAlignment="textEnd"
android:text="Top"
android:id="#+id/top_data"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_gravity="center"
android:layout_weight="0.5"
android:background="#color/alphabet_a"
android:layout_width="wrap_content"
android:layout_height="2dp" />
<ImageView
android:background="#drawable/circle1"
android:layout_width="15dp"
android:layout_height="15dp" />
<TextView
android:layout_weight="0.5"
android:layout_gravity="center"
android:background="#color/alphabet_a"
android:layout_width="wrap_content"
android:layout_height="2dp" />
</LinearLayout>
<TextView
android:padding="3dp"
android:gravity="center"
android:text="bottom"
android:id="#+id/bottom_data"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</merge>
timeline_segment.java
public class timeline_segement extends LinearLayout {
View rootView;
TextView upperText;
TextView startLine;
TextView endLine;
ImageView circleView;
TextView bottomText;
public timeline_segement(Context context) {
super(context);
init(context);
}
public timeline_segement(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public timeline_segement(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
private void init(Context context) {
rootView=inflate(context, R.layout.timeline_segment, this );
upperText=(TextView) rootView.findViewById(R.id.top_data);
bottomText=(TextView) rootView.findViewById(R.id.bottom_data);
upperText.setText("Top");
bottomText.setText("Bottom");
}
public void setUpperText(String string)
{
upperText.setText(string);
}
public void setBottomText(String string)
{
bottomText.setText(string);
}
}
Decided to answer because the comment box is kinda limiting. This is my comment:
You'll need a custom view to achieve this. You can either composite ready-made views or go full custom
If you choose to composite views, then you start by breaking down that image level by level. At the highest level, its a horizontal layout with 'TimelineCell's (or whatever you choose to call it).
A TimelineCell will basically be a vertical LinearLayout with a right aligned TextView, a View that draws the line and another center aligned TextView.
You can then create these programmatically and add them to a parent horizontal LinearLayout.
If you however choose to go full custom, Youll have to handle measuring, layouting and drawing of all the components including the text above and below the line.
Take a look at this link for a good introduction to custom views on android
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>