我应该设置片段根视图的ID吗?

时间:2015-05-04 18:37:55

标签: android android-fragments

我遇到了一个问题,即片段的根ID在被活动扩展时会被更改。我能够解决这个问题,但是我试图弄清楚是否应该始终避免在根视图上放置ID,以便在用户附加的情况下不会重命名它通过XML进行活动。

这是我的activity_main.xml

<fragment xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/fragment"
    android:name="com.example.fragmenttest.MainActivityFragment"
    tools:layout="@layout/fragment_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>

这是我的fragment_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/mylayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    tools:context=".MainActivityFragment">

    <TextView
        android:text="@string/hello_world"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

</RelativeLayout>

现在,如果我想在片段的onCreateView中引用RelativeLayout,我可以调用findViewById(R.id.mylayout)并且它可以工作。但是,如果我稍后再打电话,我就无法使用

rl = getView().findViewById(R.id.mylayout);

因为根视图的ID已更改为R.id.fragment(我可以使用它来获取RelativeLayout)。

所以我想知道我是否应该设置片段的根视图的ID,以便下一个开发人员直接在XML中使用它。

主要活动:

public class MainActivity extends ActionBarActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {

            MainActivityFragment fragment = (MainActivityFragment) getSupportFragmentManager()
                    .findFragmentById(R.id.fragment);
            fragment.doIdTest();
            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}

和MainActivityFragment:

public class MainActivityFragment extends Fragment {

    public MainActivityFragment() {
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_main, container, false);
    }

    public void doIdTest() {
        View rl = getView().findViewById(R.id.mylayout);

        if (rl == null) {
            Log.wtf("Ack!", "Can't find the RelativeLayout!");
        }

        rl = getView().findViewById(R.id.fragment);

        if (rl != null && rl instanceof RelativeLayout) {
            Log.wtf("Ack!", "ID of the relative layout is fragment!");
        }
    }
}

可在此处查看演示此问题的完整项目:https://www.dropbox.com/s/08xu4bxi84rsms3/FragmentTest.tar.gz?dl=0

2 个答案:

答案 0 :(得分:4)

我尝试了您的代码,我担心我看到的内容与您相同 - 根Id的{​​{1}}实际上是从RelativeLayout更改的R.id.myLayoutR.id.fragment。 :o

我做了一点挖掘,发现在Activity#setContentView内,它实际上调用了FragmentManager,而Fragment会调用添加到Activity的所有FragmentManager#onCreateView。然后在调用Fragment#onCreateView时调用Fragment#onCreateView

Fragment被调用时,R.id.myLayout的根视图仍为FragmentManager#onCreateView,但在调用Id之后,由于某种原因,此方法会更改mView代码的这一部分中mInnerView的{​​{1}}和Fragment的1}}:

if (id != 0) {
    fragment.mView.setId(id);
}

此时fragment.mView已设置Id - R.id.myLayout

代码中没有解释为什么会发生这种情况以及为什么需要它,但事实是它发生了。

此处参考FragmentManager#onCreateView方法的Pastebin

现在我要做的事情,就是忘记Id的{​​{1}} R.id.myLayout

例如,您可以通过RelativeLayout这样做来获得RelativeLayout

Activity

MainActivityFragment fragment = (MainActivityFragment) getSupportFragmentManager().findFragmentById(R.id.fragment); RelativeLayout rootView = (RelativeLayout) fragment.getView(); 将始终返回rootview,并且可以转换为getView。它不漂亮,但我认为它应该如何运作。

如果您想从RelativeLayout中获取RelativeLayout,只需直接调用Fragment并将其转换为getView或为其内部的根视图创建一个全局变量RelativeLayout - 这至少是我们在工作中的代码中所做的: - )

此外,如果您移除Fragment Id Fragment activity_main.xmlFragmentManager#onCreateView仍然会覆盖Id的当前RelativeLayout并且您将无法使用View#findViewById

至于为什么谷歌会覆盖Id我无法回答的问题,但在我看来,整个Fragment系统又有点摇摇欲坠。

我希望这能够揭示至少实际发生的事情: - )

答案 1 :(得分:0)

您不需要为片段的RelativeLayout设置ID。

public final class MainFragment extends Fragment {

    private TextView mTextView;
    private RelativeLayout mRoot;

    @Nullable
    @Override
    public View onCreateView(
        final LayoutInflater inflater,
        final ViewGroup container,
        final Bundle savedInstanceState
    ) {
        mRoot     = (RelativeLayout) inflater.inflate(
                R.layout.fragment_main, container);
        mTextView = (TextView) mRoot.findViewById(R.id.text);
        return mRoot;
    }
}

片段的ID可用于通过FragmentManager获取片段。

final FragmentManager fm = getFragmentManager(); // getSupportFragmentManager()
final MainFragment f     = (MainFragment) fm.findFragmentById(R.id.fragment);