I find myself needing to create a View completely in Java without knowing what concrete type the parent is.
example:
public View getView(int position, View convertView, ViewGroup parent){
if(null == convertView){
convertView = new TextView(parent.getContext());
}
((TextView) convertView).setText(getItem(position).getName());
}
Now suppose I wanted to change this so that the convertView was wrap_content in both directions. Since this is an Adapter, I'd like to avoid coupling the Adapter with the concrete type of the parent, but the LayoutParams I give it in setLayoutParams() has to be the correct concrete type otherwise the app will crash (i.e. if parent is a ListView it has to be ListView.LayoutParams, if it's a LinearLayout it must be a LinearLayout.LayoutParams, etc.). I don't want to use a switch statement either since that's just a more flexible form of coupling, and if I attach this adapter to a view I didn't anticipate I still end up with a crash. Is there a generic way to do this?
You can do this using the following code:
LayoutParams params = parent.generateLayoutParams(null);
EDIT:
The method above doesn't work because ViewGroup.generateLayoutParams()
requires android:layout_width
and android:layout_height
to be set in the passed AttributeSet
.
If you use ViewGroup.LayoutParams
with any layout then everything will work fine. But if you use LinearLayout.LayoutParams
with RelativeLayout
for example, then an exception will be thrown.
EDIT:
There's one working solution for this problem which I don't really like. The solution is to call generateLayoutParams()
with valid AttributeSet
. You can create an AttributeSet
object using at least two different approaches. One of them I've implemented:
res\layout\params.xml:
<?xml version="1.0" encoding="utf-8"?>
<view xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="20dip" />
SomeActivity.java:
private void addView(ViewGroup viewGroup, View view) {
viewGroup.addView(view);
view.setLayoutParams(generateLayoutParams(viewGroup));
}
private ViewGroup.LayoutParams generateLayoutParams(ViewGroup viewGroup) {
XmlResourceParser parser = getResources().getLayout(R.layout.params);
try {
while(parser.nextToken() != XmlPullParser.START_TAG) {
// Skip everything until the view tag.
}
return viewGroup.generateLayoutParams(parser);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
Another way to create an AttributeSet
object is to implement AttributeSet
interface and make it return android:layout_width
, android:layout_height
and other layout attributes you need.