15

親の具象型を知らなくても、Java で完全にビューを作成する必要があることに気付きました。

例:

public View getView(int position, View convertView, ViewGroup parent){
    if(null == convertView){
        convertView = new TextView(parent.getContext());
    }
    ((TextView) convertView).setText(getItem(position).getName());
}

convertView が両方向で wrap_content になるように、これを変更したいとします。これはアダプターなので、アダプターを親の具象型と結合することは避けたいのですが、 setLayoutParams() で指定する LayoutParams は正しい具象型でなければなりません。そうしないと、アプリがクラッシュします (つまり、親がListView の場合は ListView.LayoutParams である必要があり、LinearLayout の場合は LinearLayout.LayoutParams である必要があります、など)。これは結合のより柔軟な形式であるため、switch ステートメントも使用したくありません。このアダプターをビューに接続すると、予期していなかったクラッシュが発生します。これを行う一般的な方法はありますか?

4

4 に答える 4

10

次のコードを使用してこれを行うことができます。

LayoutParams params = parent.generateLayoutParams(null);

編集: 上記のメソッドは、渡された に設定する必要ViewGroup.generateLayoutParams()があるため機能しません。android:layout_widthandroid:layout_heightAttributeSet

任意のレイアウトで使用するViewGroup.LayoutParamsと、すべてが正常に機能します。ただし、たとえばLinearLayout.LayoutParamswithを使用すると、例外がスローされます。RelativeLayout

編集:この問題には、私があまり好きではない実用的な解決策が1つあります。generateLayoutParams()解決策は、 validで呼び出すことですAttributeSetAttributeSet少なくとも 2 つの異なるアプローチを使用してオブジェクトを作成できます。私が実装したそれらの1つ:

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;
}

AttributeSetオブジェクトを作成するもう 1 つの方法は、インターフェイスを実装し、必要なその他のレイアウト属性をAttributeSet返すようにすることです。android:layout_widthandroid:layout_height

于 2011-08-10T21:53:22.770 に答える
1

なぜ誰も (まだ -> 2016.05 を参照) ここでリフレクションに基づくアプローチについて言及していないのですか?

1. エントリーポイント:

 /**
 *  generates default layout params for given view group 
 *  with width and height set to WLayoutParams.RAP_CONTENT 
 *
 * @param viewParent - parent of this layout params view 
 * @param <L> - layout param class 
 * @return layout param class object 
 * @throws NoSuchMethodException
 * @throws InvocationTargetException
 * @throws IllegalAccessException
 */
@NonNull
private <L extends ViewGroup.LayoutParams> L generateDefaultLayoutParams(@NonNull ViewGroup viewParent)
        throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
    Method generateDefaultLayoutParamsMethod = ViewGroup.class.getDeclaredMethod("generateDefaultLayoutParams");
      // caution: below way to obtain method has some flaw  as we need traverse superclasses to obtain method in case we look in object and not a class             
      // = viewParent.getClass().getDeclaredMethod("generateDefaultLayoutParams");
    generateDefaultLayoutParamsMethod.setAccessible(true);
    return (L) generateDefaultLayoutParamsMethod.invoke(viewParent);
}

2.用途:

@NonNull
protected <T extends ViewGroup.LayoutParams> T createLayoutParamsForView(ViewGroup viewParent,
                                                                         @IdRes int belowViewId)
        throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
    return createLayoutParamsForView(null,null,viewParent,belowViewId);
}

@NonNull
protected <T extends ViewGroup.LayoutParams> T createLayoutParamsForView(@NonNull Context context,
                                                                         @NonNull Class<? extends ViewGroup> parentClass,
                                                                         @IdRes int belowViewId)
        throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
    return createLayoutParamsForView(context,parentClass,null,belowViewId);
}

@NonNull
private <T extends ViewGroup.LayoutParams> T createLayoutParamsForView(@Nullable Context context,
                                                                       @Nullable Class<? extends ViewGroup> parentClass,
                                                                       @Nullable ViewGroup parent,
                                                                       @IdRes int belowViewId)
        throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
    if(context == null && parent == null) throw new IllegalStateException("either context and parent class or must be non null!");
    T layoutParams = (T) (parent != null ? generateDefaultLayoutParams(parent) : generateDefaultLayoutParams(context, parentClass));
    if (belowViewId != NO_ID  && RelativeLayout.LayoutParams.class.isAssignableFrom(layoutParams.getClass())){
        ((RelativeLayout.LayoutParams)layoutParams).addRule(RelativeLayout.BELOW, belowViewId);
    }
    return layoutParams;
}

@NonNull
private <P extends ViewGroup> P instantiateParent(Class parentClass, Context context) 
        throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
    Constructor constructor = parentClass.getDeclaredConstructor(Context.class);
    constructor.setAccessible(true);
    return (P) constructor.newInstance(context);
}

@NonNull
private <L extends ViewGroup.LayoutParams, P extends ViewGroup> L generateDefaultLayoutParams(Context context, @NonNull Class<? extends ViewGroup> viewParentClass) 
        throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {
    P viewParent = instantiateParent(viewParentClass, context);
    return generateDefaultLayoutParams(viewParent);
}
于 2016-05-08T02:13:15.150 に答える
0

すべてのLayoutParamsクラスには、1 つの一般的なスーパークラスがあります: ViewGroup.LayoutParams. また、すべての一般的なレイアウト ( FrameLayoutLinearLayoutConstraintLayoutなど) はViewGroup.MarginLayoutParams、それぞれのLayoutParamsクラスの基本クラスとして使用されます。

したがって、幅、高さ、および余白だけが必要な場合は、それを作成ViewGroup.MarginLayoutParamsしてレイアウト パラメータとして の任意のサブクラスに渡すことができますViewGroup。次に何が起こるかというと、コンテナは を使用して、より一般的なViewGroup.MarginLayoutParams独自のレイアウト パラメータに自動的に変換しますprotected LayoutParams ViewGroup#generateLayoutParams(ViewGroup.LayoutParams p)

このコードは、、 などcontainerを含むすべてのクラスで機能します。LinearLayoutRelativeLayout

val layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
container.addView(view, layoutParams)
于 2019-03-15T10:46:33.530 に答える