Custom View with two TextViews - android

I want to create a custom view with 2 TextViews, with possibility change text and text appearances from xml. This view should have two state - normal and selected (TextViews style should be different for each state).
I need some example for it.

Custom views are pretty basic and there are examples all over the internet. For something simple like two text views, it's usually easiest to extend LinearLayout.
Here is the LinearLayout with two text views, arranged side by side.
res/double_text.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/left_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxLines="1"/>
<TextView
android:id="#+id/right_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxLines="1"/>
</LinearLayout>
Next we define a styleable resource block so we can add custom attributes to our custom layout.
res/values/attrs.xml
<resources>
<declare-styleable name="DoubleText">
<attr name="leftText" format="string" />
<attr name="rightText" format="string" />
<attr name="android:ems" />
</declare-styleable>
</resources>
Next the class file for DoubleText custom view. In here we pull out the custom attributes and set each of the TextViews.
DoubleTextView.java
public class DoubleTextView extends LinearLayout {
LinearLayout layout = null;
TextView leftTextView = null;
TextView rightTextView = null;
Context mContext = null;
public DoubleTextView(Context context) {
super(context);
mContext = context;
}
public DoubleTextView(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DoubleText);
String leftText = a.getString(R.styleable.DoubleText_leftText);
String rightText = a.getString(R.styleable.DoubleText_rightText);
leftText = leftText == null ? "" : leftText;
rightText = rightText == null ? "" : rightText;
String service = Context.LAYOUT_INFLATER_SERVICE;
LayoutInflater li = (LayoutInflater) getContext().getSystemService(service);
layout = (LinearLayout) li.inflate(R.layout.double_text, this, true);
leftTextView = (TextView) layout.findViewById(R.id.left_text);
rightTextView = (TextView) layout.findViewById(R.id.right_text);
leftTextView.setText(leftText);
rightTextView.setText(rightText);
a.recycle();
}
public DoubleTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mContext = context;
}
#SuppressWarnings("unused")
public void setLeftText(String text) {
leftTextView.setText(text);
}
#SuppressWarnings("unused")
public void setRightText(String text) {
rightTextView.setText(text);
}
#SuppressWarnings("unused")
public String getLeftText() {
return leftTextView.getText().toString();
}
#SuppressWarnings("unused")
public String getRightText() {
return rightTextView.getText().toString();
}
}
Finally, using the custom class is as simple as declaring it in a layout file.
<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"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
tools:showIn="#layout/activity_main"
tools:context=".MainActivity">
<TextView
android:id="#+id/main_text"
android:text="Hello World!"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#color/custom"/>
<example.com.test.DoubleTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:leftText="Text Left"
app:rightText="Text Right"
android:layout_below="#+id/main_text"/>
</RelativeLayout>
Easy peasy.

Related

SVG/VectorDrawable issue in android

I have used svg files in my Android project. There are issues in Android 4.4 or lower versions. I have tried these solutions app:srcCompat, vectorDrawables.useSupportLibrary = true in gradle file and AppCompatDelegate.setCompatVectorFromResourcesEnabled(true); in static block of BaseActivity. Other than gridview, images are not shown in app.
Instead of using above 3 solutions, just replace your ImageView with android.support.v7.widget.AppCompatImageView. No need to do any extra effort.
Note:- TextView, EditText and other classes, which use drawableRight and drawableLeft are not supported. For them, create your own compound view class with TextView or EditText and AppCompatImageView in a FrameLayout or RelativeLayout. Example of drawableRight inside EditText:-
Layout file
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<EditText
android:id="#+id/edt_search"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text"
android:maxLines="1"
android:paddingEnd="40dp"
android:paddingLeft="5dp"
android:paddingRight="40dp"
android:paddingStart="5dp" />
<android.support.v7.widget.AppCompatImageView
android:id="#+id/search"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_gravity="right|center_vertical"
android:layout_margin="8dp"
android:src="#drawable/ic_svg_search" />
</FrameLayout>
Code
public class EditTextWithDrawable extends FrameLayout {
public AppCompatImageView mDrawableRight;
public EditText mAppEditText;
public AppEditTextWithDrawable(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs);
}
private void init(AttributeSet attrs) {
if (attrs != null && !isInEditMode()) {
LayoutInflater inflater = (LayoutInflater) getContext()
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.compound_view, this, true);
mDrawableRight = (AppCompatImageView) ((FrameLayout) getChildAt(0)).getChildAt(1);
mAppEditText = (EditText) ((FrameLayout) getChildAt(0)).getChildAt(0);
TypedArray attributeArray = getContext().obtainStyledAttributes(
attrs,
R.styleable.EditTextWithDrawable);
int drawableRes =
attributeArray.getResourceId(
R.styleable.EditTextWithDrawable_drawableRightSVG, -1);
if (drawableRes != -1) {
mDrawableRight.setImageResource(drawableRes);
}
attributeArray.recycle();
}
}
}
attrs.xml file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="AppEditTextWithDrawable">
<attr name="drawableRightSVG" format="reference" />
</declare-styleable>
</resources>
Convert SVG file into XML and use it from Drawable folder. Check this .

Android #layout/list_item not resolved into its int value

I would like to create a custom linear layout (to work as some basic list) which accepts a custom parameter from xml, like this:
<MyLinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
myns:layout_to_inflate="#layout/list_item"/>
Then, use it in the constructor:
String layoutToInflate = attrs.getAttributeValue(NAMESPACE, "layout_to_inflate");
I get "#layout/list_item". It is not resolved by the system into the int value which is accessible in R.layout.list_item.
Sure I can parse it and use Resources.getIdentifier to look up the ID, then inflate it, but I think that is not the way.
Then... what is the way? Can I get the system to resolve it directly into the int?
UPDATE:
list_item.xml:
<TextView 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"
android:text="Text here!" />
activity_main.xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:myns="http://com.example.layoutinflate"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" >
<com.example.layoutinflate.MyLinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
myns:layout_to_inflate="#layout/list_item" />
</RelativeLayout>
Contents MyLinearLayout.java:
public class MyLinearLayout extends LinearLayout {
private static final String TAG = MyLinearLayout.class.getSimpleName();
public MyLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray styledAttributes = context.obtainStyledAttributes(attrs, R.styleable.MyLinearLayout);
int layoutId = styledAttributes.getResourceId(R.styleable.MyLinearLayout_layout_to_inflate, -1);
int layoutIdInt = styledAttributes.getInt(R.styleable.MyLinearLayout_layout_to_inflate, -1);
String str = styledAttributes.getString(R.styleable.MyLinearLayout_layout_to_inflate);
Log.d(TAG, Integer.toString(layoutId) + ";" + str + ";" + layoutIdInt); //-1; null; -1
styledAttributes.recycle();
}
}
Thanks!
Make sure you correctly define this custom attribute inside your attrs.xml. It has to be like this:
<attr name="layout_to_inflate" format="reference" />
<declare-styleable name="MyLinearLayout">
<attr name="layout_to_inflate" />
</declare-styleable>
Then you can get this value inside your MyLinearLayout object with this:
int layoutToInflateId = attributes.getResourceId(R.styleable.MyLinearLayout_layout_to_inflate, R.layout.<default_layout_to_inflate>);

Custom View which has subviews with same id

I've implemented a custom view with hosts two subviews which are identified by an id in the xml. When using two of this custom view in the same layout I run into the problem that it is random which custom view is chosen.
How can I write a custom view with different view ids that can be multiply used in the same layout?
Here is the xml of the custom view:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
<EditText
android:id="#+id/clearable_edit"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:inputType="textCapWords"
android:paddingRight="35dip" />
<Button
android:id="#+id/clearable_button_clear"
android:layout_width="30dip"
android:layout_height="30dip"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="5dip"
android:background="#drawable/clear_button" />
</RelativeLayout>
The id (android:id="#+id/clearable_edit") of the EditText is the problem here.
Usage of custom view:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<com.custom.package.ClearableEditText
android:id="#+id/arr_location"
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
</com.custom.package.ClearableEditText>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<com.custom.package.ClearableEditText
android:id="#+id/dep_location"
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
</com.custom.package.ClearableEditText>
</LinearLayout>
In this example the views of type "ClearableEditText" share the same id of their EditText subview.
Here is the code for ClearableEditText:
public class ClearableEditText extends RelativeLayout {
private LayoutInflater inflater = null;
private EditText edit_text;
private Button btn_clear;
public ClearableEditText(Context context, AttributeSet attrs, int defStyle){
super(context, attrs, defStyle);
initViews();
}
public ClearableEditText(Context context, AttributeSet attrs){
super(context, attrs);
initViews();
}
public ClearableEditText(Context context){
super(context);
initViews();
}
private void initViews(){
inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.clearable_edittext, this, true);
edit_text = (EditText) view.findViewById(R.id.clearable_edit);
btn_clear = (Button) findViewById(R.id.clearable_button_clear);
btn_clear.setVisibility(RelativeLayout.INVISIBLE);
}
}
First fetch parent View like this:
View v1 = findViewById(R.id.arr_location);
and then
EditText ed1 = (EditText)v1.findViewById(R.id.clearable_edit);
Similarly
View v2 = findViewById(R.id.dep_location);
EditText ed2 = (EditText)v2.findViewById(R.id.clearable_edit);
This way you can add as many ClearableEditText as you want having same id for EditText and Button. Just make sure that every ClearableEditText has different id e.g. in this case R.id.arr_location and R.id.dep_location.
I've found a solution.
I've added a method to ClearableEditText where you can set the id of the underlying EditText from outside the object and set it with a new id.
Here is a code sample:
//inside ClearableEditText
public void setEditId(int id){
edit_text.setId(id);
}
//somewhere else
departureLocation = (ClearableEditText)view.findViewById(R.id.dep_location);
departureLocation.setEditId(R.id.clearable1);
arrivalLocation = (ClearableEditText)view.findViewById(R.id.arr_location);
arrivalLocation.setEditId(R.id.clearable2);
The Ids are created with a "ids.xml" in the values folder, which causes eclipse/ADT to create a placeholder id for the entered items
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- This file is used to create unique ids for custom views, which will be used more
than once in the same layout file. Using unique ids prevents the custom view from getting
the wrong state. -->
<item name="clearable1" type="id"></item>
<item name="clearable2" type="id"></item>
</resources>

declare-styleable drawableTop

I try implement compound view for my dashboard activity. It's Button with TextView. Need for my theme.
I have attr.xml file
<declare-styleable name="DashboardButton">
<attr name="drawableTop" format="reference"/> <!-- i want set android:drawableTop of button-->
<attr name="btnText" format="string" /> <!-- text about button functionality-->
<attr name="tvText" format="string" /> <!-- additional information -->
</declare-styleable>
also have dashboard_button.xml layout
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<Button
android:id="#+id/btn"
style="#style/DashboardButton"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true" />
<TextView
style="#style/btn_add_info"
android:id="#+id/txtView"
android:text="0"/>
</RelativeLayout>
also have custom component DashboardButton
public class DashboardButton extends RelativeLayout {
private TextView txtView;
private Button btn;
public DashboardButton(Context context) {
super(context);
}
public DashboardButton(Context context, AttributeSet attrs) {
super(context, attrs);
LayoutInflater inflater = LayoutInflater.from(context);
inflater.inflate(R.layout.dashboard_button, this);
loadViews(attrs);
}
public DashboardButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
LayoutInflater inflater = LayoutInflater.from(context);
inflater.inflate(R.layout.dashboard_button, this);
loadViews(attrs);
}
private void loadViews(AttributeSet attrs) {
txtView = (TextView) findViewById(R.id.txtView);
btn = (Button) findViewById(R.id.btn);
TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.DashboardButton);
txtView.setText(a.getString(R.styleable.DashboardButton_tvText));
btn.setText(a.getString(R.styleable.DashboardButton_btnText));
//i think issue here but can't understand what i should do
Drawable topDrawable = a.getDrawable(R.styleable.DashboardButton_drawableTop);
btn.setCompoundDrawables(null, topDrawable, null, null);
a.recycle();
}
public void setTxtViewText(CharSequence text) {
txtView.setText(text);
}
}
and finally i have
<my.package.name.DashboardButton
android:id="#+id/Btn"
style="#style/DashboardButton"
app:btnText="#string/my_function"
app:tvText="#string/add_info"
app:drawableTop="#drawable/function_logo">
</my.package.name.DashboardButton>
All work fine, except app:drawableTop drawable not load at run time, I dont see drawable. Can you help me by advice?
You need to set the bounds for your drawable:
topDrawable.setBounds( new Rect( 0, 0, w, h ) );
or alternatively use:
btn.setCompoundDrawablesWithIntrinsicBounds(null, topDrawable, null, null);

Create a custom View by inflating a layout?

I am trying to create a custom View that would replace a certain layout that I use at multiple places, but I am struggling to do so.
Basically, I want to replace this:
<RelativeLayout
android:id="#+id/dolphinLine"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:background="#drawable/background_box_light_blue"
android:padding="10dip"
android:layout_margin="10dip">
<TextView
android:id="#+id/dolphinTitle"
android:layout_width="200dip"
android:layout_height="100dip"
android:layout_alignParentLeft="true"
android:layout_marginLeft="10dip"
android:text="#string/my_title"
android:textSize="30dip"
android:textStyle="bold"
android:textColor="#2E4C71"
android:gravity="center"/>
<Button
android:id="#+id/dolphinMinusButton"
android:layout_width="100dip"
android:layout_height="100dip"
android:layout_toRightOf="#+id/dolphinTitle"
android:layout_marginLeft="30dip"
android:text="#string/minus_button"
android:textSize="70dip"
android:textStyle="bold"
android:gravity="center"
android:layout_marginTop="1dip"
android:background="#drawable/button_blue_square_selector"
android:textColor="#FFFFFF"
android:onClick="onClick"/>
<TextView
android:id="#+id/dolphinValue"
android:layout_width="100dip"
android:layout_height="100dip"
android:layout_marginLeft="15dip"
android:background="#android:drawable/editbox_background"
android:layout_toRightOf="#+id/dolphinMinusButton"
android:text="0"
android:textColor="#2E4C71"
android:textSize="50dip"
android:gravity="center"
android:textStyle="bold"
android:inputType="none"/>
<Button
android:id="#+id/dolphinPlusButton"
android:layout_width="100dip"
android:layout_height="100dip"
android:layout_toRightOf="#+id/dolphinValue"
android:layout_marginLeft="15dip"
android:text="#string/plus_button"
android:textSize="70dip"
android:textStyle="bold"
android:gravity="center"
android:layout_marginTop="1dip"
android:background="#drawable/button_blue_square_selector"
android:textColor="#FFFFFF"
android:onClick="onClick"/>
</RelativeLayout>
By this:
<view class="com.example.MyQuantityBox"
android:id="#+id/dolphinBox"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:myCustomAttribute="#string/my_title"/>
So, I do not want a custom layout, I want a custom View (it should not be possible for this view to have child).
The only thing that could change from one instance of a MyQuantityBox to another is the title. I would very much like to be able to specify this in the XML (as I do on the last XML line)
How can I do this? Should I put the RelativeLayout in a XML file in /res/layout and inflate it in my MyBoxQuantity class? If yes how do I do so?
Thanks!
A bit old, but I thought sharing how I'd do it, based on chubbsondubs' answer:
I use FrameLayout (see Documentation), since it is used to contain a single view, and inflate into it the view from the xml.
Code following:
public class MyView extends FrameLayout {
public MyView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initView();
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
}
public MyView(Context context) {
super(context);
initView();
}
private void initView() {
inflate(getContext(), R.layout.my_view_layout, this);
}
}
Here is a simple demo to create customview (compoundview) by inflating from xml
attrs.xml
<resources>
<declare-styleable name="CustomView">
<attr format="string" name="text"/>
<attr format="reference" name="image"/>
</declare-styleable>
</resources>
CustomView.kt
class CustomView #JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) :
ConstraintLayout(context, attrs, defStyleAttr) {
init {
init(attrs)
}
private fun init(attrs: AttributeSet?) {
View.inflate(context, R.layout.custom_layout, this)
val image_thumb = findViewById<ImageView>(R.id.image_thumb)
val text_title = findViewById<TextView>(R.id.text_title)
val ta = context.obtainStyledAttributes(attrs, R.styleable.CustomView)
try {
val text = ta.getString(R.styleable.CustomView_text)
val drawableId = ta.getResourceId(R.styleable.CustomView_image, 0)
if (drawableId != 0) {
val drawable = AppCompatResources.getDrawable(context, drawableId)
image_thumb.setImageDrawable(drawable)
}
text_title.text = text
} finally {
ta.recycle()
}
}
}
custom_layout.xml
We should use merge here instead of ConstraintLayout because
If we use ConstraintLayout here, layout hierarchy will be ConstraintLayout->ConstraintLayout -> ImageView + TextView => we have 1 redundant ConstraintLayout => not very good for performance
<?xml version="1.0" encoding="utf-8"?>
<merge 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"
tools:parentTag="android.support.constraint.ConstraintLayout">
<ImageView
android:id="#+id/image_thumb"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:ignore="ContentDescription"
tools:src="#mipmap/ic_launcher" />
<TextView
android:id="#+id/text_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="#id/image_thumb"
app:layout_constraintStart_toStartOf="#id/image_thumb"
app:layout_constraintTop_toBottomOf="#id/image_thumb"
tools:text="Text" />
</merge>
Using
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
android:orientation="vertical">
<your_package.CustomView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#f00"
app:image="#drawable/ic_android"
app:text="Android" />
<your_package.CustomView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#0f0"
app:image="#drawable/ic_adb"
app:text="ADB" />
</LinearLayout>
Result
See full code on:
Github
Yes you can do this. RelativeLayout, LinearLayout, etc are Views so a custom layout is a custom view. Just something to consider because if you wanted to create a custom layout you could.
What you want to do is create a Compound Control. You'll create a subclass of RelativeLayout, add all our your components in code (TextView, etc), and in your constructor you can read the attributes passed in from the XML. You can then pass that attribute to your title TextView.
http://developer.android.com/guide/topics/ui/custom-components.html
Use the LayoutInflater as I shown below.
public View myView() {
View v; // Creating an instance for View Object
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = inflater.inflate(R.layout.myview, null);
TextView text1 = v.findViewById(R.id.dolphinTitle);
Button btn1 = v.findViewById(R.id.dolphinMinusButton);
TextView text2 = v.findViewById(R.id.dolphinValue);
Button btn2 = v.findViewById(R.id.dolphinPlusButton);
return v;
}
In practice, I have found that you need to be a bit careful, especially if you are using a bit of xml repeatedly. Suppose, for example, that you have a table that you wish to create a table row for each entry in a list. You've set up some xml:
In my_table_row.xml:
<?xml version="1.0" encoding="utf-8"?>
<TableRow xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent" android:id="#+id/myTableRow">
<ImageButton android:src="#android:drawable/ic_menu_delete" android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="#+id/rowButton"/>
<TextView android:layout_height="wrap_content" android:layout_width="wrap_content" android:textAppearance="?android:attr/textAppearanceMedium" android:text="TextView" android:id="#+id/rowText"></TextView>
</TableRow>
Then you want to create it once per row with some code. It assume that you have defined a parent TableLayout myTable to attach the Rows to.
for (int i=0; i<numRows; i++) {
/*
* 1. Make the row and attach it to myTable. For some reason this doesn't seem
* to return the TableRow as you might expect from the xml, so you need to
* receive the View it returns and then find the TableRow and other items, as
* per step 2.
*/
LayoutInflater inflater = (LayoutInflater)getBaseContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View v = inflater.inflate(R.layout.my_table_row, myTable, true);
// 2. Get all the things that we need to refer to to alter in any way.
TableRow tr = (TableRow) v.findViewById(R.id.profileTableRow);
ImageButton rowButton = (ImageButton) v.findViewById(R.id.rowButton);
TextView rowText = (TextView) v.findViewById(R.id.rowText);
// 3. Configure them out as you need to
rowText.setText("Text for this row");
rowButton.setId(i); // So that when it is clicked we know which one has been clicked!
rowButton.setOnClickListener(this); // See note below ...
/*
* To ensure that when finding views by id on the next time round this
* loop (or later) gie lots of spurious, unique, ids.
*/
rowText.setId(1000+i);
tr.setId(3000+i);
}
For a clear simple example on handling rowButton.setOnClickListener(this), see Onclicklistener for a programmatically created button.
There are multiple answers which point the same way in different approaches, I believe the below is the simplest approach without using any third-party libraries, even you can use it using Java.
In Kotlin;
Create values/attr.xml
<resources>
<declare-styleable name="DetailsView">
<attr format="string" name="text"/>
<attr format="string" name="value"/>
</declare-styleable>
</resources>
Create layout/details_view.xml file for your view
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/text_label"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="0.5"
tools:text="Label" />
<TextView
android:id="#+id/text_value"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="0.5"
tools:text="Value" />
</LinearLayout>
</merge>
Create the custom view widget DetailsView.kt
import android.content.Context
import android.content.res.TypedArray
import android.util.AttributeSet
import android.view.View
import android.widget.LinearLayout
import android.widget.TextView
import com.payable.taponphone.R
class DetailsView #JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : LinearLayout(context, attrs, defStyleAttr) {
private val attributes: TypedArray = context.obtainStyledAttributes(attrs, R.styleable.DetailsView)
private val view: View = View.inflate(context, R.layout.details_view, this)
init {
view.findViewById<TextView>(R.id.text_label).text = attributes.getString(R.styleable.DetailsView_text)
view.findViewById<TextView>(R.id.text_value).text = attributes.getString(R.styleable.DetailsView_value)
}
}
That's it now you can call the widget anywhere in your app as below
<com.yourapp.widget.DetailsView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:text="Welcome"
app:value="Feb" />
A simple Custom View using Kotlin
Replace FrameLayout with whatever view you Like to extend
/**
* Simple Custom view
*/
class CustomView#JvmOverloads
constructor(context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0)
: FrameLayout(context, attrs, defStyleAttr) {
init {
// Init View
val rootView = (getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater)
.inflate(R.layout.custom_layout, this, true)
val titleView= rootView.findViewById(id.txtTitle)
// Load Values from XML
val attrsArray = getContext().obtainStyledAttributes(attrs, R.styleable.CutsomView, defStyleAttr, 0)
val titleString = attrsArray.getString(R.styleable.cutomAttrsText)
attrsArray.recycle()
}
}

Categories

Resources