在通货膨胀期间如何引用另一个控件?

时间:2013-05-23 03:51:48

标签: android android-layout android-view android-custom-view attr

我试图通过XML引用兄弟控件。

声明属性以引用MyTextView中的id:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="MyTextView">
        <attr name="valueTextViewId" format="reference" />
    </declare-styleable>
</resources>

fragment_example.xml - 如何使用自定义属性:

<!-- Declare a "Title" text view that references a "Value" -->
<com.example.MyTextView
    android:id="@+id/foo"
    example:valueTextViewId="@id/bar"
    ... />

<!-- Depending on the "text" attribute of this "Value" textview -->
<!-- Do something within "Title" textview -->
<com.example.MyTextView android:id="@+id/bar" />

MyFragment.java - 对控件进行充气

public View onCreateView(LayoutInflater inflater, ViewGroup container, 
        Bundle savedInstanceState) {
        // calls MyTextView Ctor
    View v = inflater.inflate(R.layout.fragment_example, container, false);
}

MyTextView类构造函数 - 在通货膨胀期间使用引用的textview执行某些操作:

public TextView(Context context, AttributeSet attrs) {
    super(context, attrs);

    TypedArray a = ctx.obtainStyledAttributes(attrs, R.styleable.MyTextView);
    int refId = a.getResourceId(R.styleable.MyTextView_valueTextViewId);

    // Updated to use context
    if (refId > -1 && context instanceof Activity) {
        Activity a = (Activity)context;
        View v = a.findViewById(refId);

        // THE PROBLEM: v is null
        if (v != null) {
            // In my case, I want to check if the "Value" textview
            // is empty. If so I will set "this" textColor to gray
        }
    }
}
在此示例中,

v始终为null。我假设因为在布局通胀期间,控件尚未添加。另一件需要注意的是,这是Fragment,因此这可能是我无法在父活动中找到视图的原因。

是否可以像这样引用另一个控件?

4 个答案:

答案 0 :(得分:2)

  

是否可以像这样引用另一个控件?

可以从View引用另一个View

但是不建议在View构造函数中进行属性检查。
View inflation期间,无法保证任何特定View在任何其他first_layout.xml之前被实例化。

比较这两种布局:
<com.example.MyTextView ... android:id="@+id/foo" example:valueTextViewId="@+id/bar" /> <com.example.MyTextView ... android:id="@+id/bar" />

second_layout.xml

<com.example.MyTextView ... android:id="@+id/bar" /> <com.example.MyTextView ... android:id="@+id/foo" example:valueTextViewId="@+id/bar" />

View

在此示例中,很明显,从构造函数检查属性将无法在其中一个布局中工作。

我同意可以将引用存储到View中的其他public MyTextView(Context context, AttributeSet attrs) { super(context, attrs); TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MyTextView); mReferenceId = a.getResourceId(R.styleable.MyTextView_valueTextViewId); ... } private int mReferenceId; public View getReferenceViewFromActivity() { if (getContext() instanceof Activity) { return ((Activity)getContext()).findViewById(mReferenceId); return null; } public View getReferenceView(View view) { return view.findViewById(mReferenceId); }

Activity

但你绝对应该在Fragment@Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); MyTextView myTextView = (MyTextView)view.findViewById(R.id.foo); MyReferenceView refView = (MyReferenceView)myTextView.getReferenceView(view); // // do property checking // } 内进行任何及所有财产检查:

{{1}}

答案 1 :(得分:1)

如果bar的id中有id为bar的textview,你可以这样做。

<com.example.MyTextView
    android:id="@+id/foo"
    ...
    android:tag="bar" />

<com.example.MyTextView android:id="@+id/bar" />

public TextView(Context context, AttributeSet attrs) {
    super(context, attrs);

      int barId = getResources().getIdentifier(getTag(), "id", packageName);
      TextView bar = mActivity.findViewById(barId);

    if (bar.getText() == "") {
        // Gray out this "title" textview
        setColor(android.R.color.gray);
    }

    // maybe set a text change listener to bar to make it future-proof
}

我只是将id作为MyTextView上的标记传递,因此您不需要创建新属性。

答案 2 :(得分:1)

将引用保存在构造函数中的私有字段中。在您的情况下,将refId保存在私有字段中。然后在onMeasure函数中使用它们。


我建议你不要使用获取引用视图的方法。如果你看一下通常情况,例如RelativeView的孩子的layout_toLeftOf,你会发现id始终是RelativeView的一个子节点,因此,它的兄弟姐妹目前来看。在这种情况下,通过使用getParent()获取父级,将其转换为ViewGroup(不一定),并使用findViewById查找带引用的视图,可以轻松获取视图。如果你可以做这种限制(id应该是兄弟姐妹),你可以摆脱对上下文的这种依赖,这最终会使你的视图无法使用。您可能最好使用setBla()而不是使用自己的属性来设置视图(如果未调用此setter,则可能会在onMeasure中抛出运行时错误。)

答案 3 :(得分:1)

据我所知,无法保证在Activity's Fragment's方法中完成onCreateView()布局。

您可以尝试这种方法:

@Override
public void onActivityCreated(Bundle savedInstanceState){
    mView.customMethodToSetTextColor(...)
}
在活动创建完成时以及onActivityCreated() lifecycle中的onCreateView()之后调用

Fragment