Android custom view group delegate addView
View
s inflated from a layout - like your example TextView
- are not added to their parent ViewGroup
with addView(View child)
, which is why overriding just that method didn't work for you. You want to override addView(View child, int index, ViewGroup.LayoutParams params)
, which all of the other addView()
overloads end up calling.
In that method, check if the child being added is one of your two special FrameLayout
s. If it is, let the super
class handle the add. Otherwise, add the child to your container FrameLayout
.
public class CustomFrameLayout extends FrameLayout {
private final FrameLayout topLayout;
private final FrameLayout containerLayout;
...
public CustomFrameLayout(Context context, AttributeSet attrs) {
super(context, attrs);
LayoutInflater.from(context).inflate(R.layout.custom, this, true);
topLayout = (FrameLayout) findViewById(R.id.frame_layout_top);
containerLayout = (FrameLayout) findViewById(R.id.frame_layout_child_container);
}
@Override
public void addView(View child, int index, ViewGroup.LayoutParams params) {
final int id = child.getId();
if (id == R.id.frame_layout_top || id == R.id.frame_layout_child_container) {
super.addView(child, index, params);
}
else {
containerLayout.addView(child, index, params);
}
}
}
How to use View Binding on custom views
Just inform the root, and whether you want to attach to it
init { // inflate binding and add as view
binding = ResultProfileBinding.inflate(LayoutInflater.from(context), this)
}
or
init { // inflate binding and add as view
binding = ResultProfileBinding.inflate(LayoutInflater.from(context), this, true)
}
which inflate method to use will depend on the root layout type in xml.
Android custom component doesn't display its children
When extending ViewGroup
directly, you need to handle measuring and laying out the child View
s yourself, or they never get sized or positioned correctly. Oftentimes, it's simpler to extend a ViewGroup
subclass that already handles that stuff. In this case, you might as well extend RelativeLayout
, since that's what's actually holding the internal View
s, and the ViewGroup
wrapping it is rather unnecessary.
The parent RelativeLayout
in the internal layout XML is then redundant, and can be replaced with <merge>
tags, which will cause the child View
s to be added directly to your RelativeLayout
subclass when inflated.
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<RelativeLayout
android:id="@+id/field_set_content"
... />
<TextView
android:id="@+id/field_set_label"
... />
</merge>
We can further simplify things by setting up the internal structure in the constructor(s), and putting the child View
s in the right place as they're added, rather than juggling all of that around in onFinishInflate()
. For example:
public class FieldSet extends RelativeLayout {
final ViewGroup vg;
public FieldSet(Context context, AttributeSet attrs) {
super(context, attrs);
LayoutInflater.from(context).inflate(R.layout.field_set, this, true);
vg = (ViewGroup) findViewById(R.id.field_set_content);
}
@Override
public void addView(View child, int index, ViewGroup.LayoutParams params) {
final int id = child.getId();
if (id == R.id.field_set_content || id == R.id.field_set_label) {
super.addView(child, index, params);
}
else {
vg.addView(child, index, params);
}
}
}
Android custom view: Delegate attributes to controls inside of view
If you want to just use the android style attributes you could do something like the following.
In this example it should pick up the text attribute if you defined it in the xml when creating the InputView.
init {
attrs?.let {
val typedArray = context.obtainStyledAttributes(attrs, STYLE_ATTRIBUTES)
val text = typedArray.getText(0)
typedArray.recycle()
}
}
companion object {
private val STYLE_ATTRIBUTES = intArrayOf(
android.R.attr.text
)
}
Android ViewBinding with CustomView
ViewDataBinding.inflate
doesn't generate of child view accessor inside custom view.
thus, you can't touch line1(TextView) via only use ViewDataBinding
.
If you don't want using findViewById
or kotlin synthetic
, MyCustomView
also needs to apply ViewDataBinding
. try as below.
CustomView
class MyCustomView @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : LinearLayout(context, attrs, defStyleAttr) {
private val binding =
CustomLayoutBinding.inflate(LayoutInflater.from(context), this, true)
val line1
get() = binding.line1
val line2
get() = binding.line2
}
MainActivity
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = ActivityMainBinding.inflate(LayoutInflater.from(this))
setContentView(binding.root)
with(binding.customView) {
line1.text = "Hello"
line2.text = "World"
}
}
Can you set a view as a property of another view in an XML layout file?
Yes, you can.
You can create a Custom View by extending the GridView class and add some logic through attributes. This will not work as an attached property from XAML (Like Grid.Column or Grid.Row from XAML UWP) but you can do something like this:
<com.teste.widget.MarqueIVGridView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:my_header="@layout/my_header"
/>
Don't forget to add the namespace at the root of your layout:
xmlns:app="http://schemas.android.com/apk/res-auto"
Google has this sample:
HeaderGridView
It uses a different approach, if you copy this class you will just need to use this "HeaderGridView" and call addHeaderView method from it sending your header view inflated.
Feel free to ask any question and It will be a pleasure to answer.
Related Topics
Android Studio Fails to Build New Project, Timed Out While Wating for Slave Aapt Process
Using Onsaveinstancestate with Fragments in Backstack
How to Use Front and Back Camera at Same Time in Android
How to Write a Custom Filter for Listview with Arrayadapter
How to Get Number of Lines of Textview
Get Image from the Gallery and Show in Imageview
Highlight Listview Selected Row
How to Create a Database in Android
Problem Inflating Custom View for Alertdialog in Dialogfragment
Send Post Request with Params Using Retrofit
Android How to Runonuithread in Other Class
How to Change Style of a Default Edittext
How to Read CPU Frequency on Android Device
Adb Got Two Same Serial Numbers When Connected to Two Smart Phones