我遇到了一个问题,即片段的根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
答案 0 :(得分:4)
我尝试了您的代码,我担心我看到的内容与您相同 - 根Id
的{{1}}实际上是从RelativeLayout
更改的R.id.myLayout
到R.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.xml
,FragmentManager#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);