6

我正在尝试通过 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. 我假设是因为在 Layout Inflation 期间,尚未添加控件。另一件需要注意的是,这是在 a 中Fragment,因此这可能是我无法在父活动中找到视图的原因。

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

4

4 回答 4

2

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

可以View从 a中引用另一个View

但是不建议在a的构造函数中进行属性检查View
无法保证在View 膨胀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在 a 中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);
}

但是您绝对应该在Activityor中进行任何和所有属性检查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
    //
}
于 2013-06-07T20:09:37.930 回答
1

据我所知,不能保证在该方法Activity's中创建完布局。Fragment's onCreateView()

您可以尝试这种方法:

@Override
public void onActivityCreated(Bundle savedInstanceState){
    mView.customMethodToSetTextColor(...)
}

onActivityCreated()在 Activity 创建完成时调用,onCreateView()Fragment 生命周期之后调用。

于 2013-06-08T09:23:26.390 回答
1

如果在 bar 的 id 中可以使用带有 bar id 的 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,因此您无需创建新属性。

于 2013-05-23T05:01:14.450 回答
1

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


我建议您不要使用获取引用视图的方法。如果您查看通常的情况,例如 RelativeView 的 children's layout_toLeftOf,您会注意到 id 始终是 RelativeView 的子项之一,因此是当前视图的兄弟。getParent()在这种情况下,通过获取父级,使用,将其强制转换为 ViewGroup(不一定),并通过引用找到视图,使用 很容易获得视图findViewById。如果你能做到这种限制(id 应该是兄弟),你也许可以摆脱对上下文的依赖,这最终会使你的视图不可用。您最好使用 setBla() 而不是使用您自己的属性来设置视图(如果未调用此设置器,可能会在您的 onMeasure 中引发运行时错误)。

于 2013-06-08T01:38:14.230 回答