Android 如何使用编程创建的内容视图向活动添加片段
我想向以编程方式实现其布局的活动添加一个片段。我查看了片段文档,但是没有太多的例子来描述我所需要的。以下是我尝试编写的代码类型:Android 如何使用编程创建的内容视图向活动添加片段,android,android-3.0-honeycomb,android-fragments,Android,Android 3.0 Honeycomb,Android Fragments,我想向以编程方式实现其布局的活动添加一个片段。我查看了片段文档,但是没有太多的例子来描述我所需要的。以下是我尝试编写的代码类型: public class DebugExampleTwo extends Activity { private ExampleTwoFragment mFragment; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate
public class DebugExampleTwo extends Activity {
private ExampleTwoFragment mFragment;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FrameLayout frame = new FrameLayout(this);
if (savedInstanceState == null) {
mFragment = new ExampleTwoFragment();
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.add(frame.getId(), mFragment).commit();
}
setContentView(frame);
}
}
此代码已编译,但在开始时崩溃,可能是因为my
FragmentTransaction.add()
不正确。正确的方法是什么?事实证明,该代码存在不止一个问题。片段不能以这种方式声明,在与活动相同的java文件中,但不能作为公共内部类。框架期望片段的构造函数(没有参数)是公共的和可见的。将片段作为一个内部类移动到活动中,或者为片段创建一个新的java文件修复了这一问题
第二个问题是,以这种方式添加片段时,必须传递对片段的包含视图的引用,并且该视图必须具有自定义id。使用默认id将使应用程序崩溃。以下是更新的代码:
public class DebugExampleTwo extends Activity {
private static final int CONTENT_VIEW_ID = 10101010;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FrameLayout frame = new FrameLayout(this);
frame.setId(CONTENT_VIEW_ID);
setContentView(frame, new LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
if (savedInstanceState == null) {
Fragment newFragment = new DebugExampleTwoFragment();
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.add(CONTENT_VIEW_ID, newFragment).commit();
}
}
public static class DebugExampleTwoFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
EditText v = new EditText(getActivity());
v.setText("Hello Fragment!");
return v;
}
}
}
以下是我在阅读后得出的结论: 科特林 如果您正在使用Kotlin,请务必查看Google提供的内容,或者自己编写
public abstract class SingleFragmentActivity extends Activity {
public static final String FRAGMENT_TAG = "single";
private Fragment fragment;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState == null) {
fragment = onCreateFragment();
getFragmentManager().beginTransaction()
.add(android.R.id.content, fragment, FRAGMENT_TAG)
.commit();
} else {
fragment = getFragmentManager().findFragmentByTag(FRAGMENT_TAG);
}
}
public abstract Fragment onCreateFragment();
public Fragment getFragment() {
return fragment;
}
}
使用
读完所有答案后,我想出了一个优雅的方法:
public class MyActivity extends ActionBarActivity {
Fragment fragment ;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FragmentManager fm = getSupportFragmentManager();
fragment = fm.findFragmentByTag("myFragmentTag");
if (fragment == null) {
FragmentTransaction ft = fm.beginTransaction();
fragment =new MyFragment();
ft.add(android.R.id.content,fragment,"myFragmentTag");
ft.commit();
}
}
基本上,您不需要添加frameLayout作为片段的容器,而是可以直接将片段添加到android根视图容器中
重要提示:不要像这里显示的大多数方法那样使用replace fragment,除非您不介意在onreseation过程中丢失片段变量实例状态
public class Example1 extends FragmentActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
DemoFragment fragmentDemo = (DemoFragment)
getSupportFragmentManager().findFragmentById(R.id.frame_container);
//above part is to determine which fragment is in your frame_container
setFragment(fragmentDemo);
(OR)
setFragment(new TestFragment1());
}
// This could be moved into an abstract BaseActivity
// class for being re-used by several instances
protected void setFragment(Fragment fragment) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction =
fragmentManager.beginTransaction();
fragmentTransaction.replace(android.R.id.content, fragment);
fragmentTransaction.commit();
}
}
要将片段添加到活动或FramenActivity中,需要
容器。该容器应为“Framelayout
”,可以是
包含在xml中,或者您可以使用默认容器
如“android.R.id.content
”删除或替换
活动
main.xml
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent" >
<!-- Framelayout to display Fragments -->
<FrameLayout
android:id="@+id/frame_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ImageView
android:id="@+id/imagenext"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_margin="16dp"
android:src="@drawable/next" />
</RelativeLayout>
对于API级别17或更高级别,将解决此问题。实用程序方法提供了一个在生成时未使用的唯一id。要在Kotlin中以编程方式将片段附加到活动,可以查看以下代码:
MainActivity.kt
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// create fragment instance
val fragment : FragmentName = FragmentName.newInstance()
// for passing data to fragment
val bundle = Bundle()
bundle.putString("data_to_be_passed", DATA)
fragment.arguments = bundle
// check is important to prevent activity from attaching the fragment if already its attached
if (savedInstanceState == null) {
supportFragmentManager
.beginTransaction()
.add(R.id.fragment_container, fragment, "fragment_name")
.commit()
}
}
}
}
class FragmentName : Fragment() {
companion object {
fun newInstance() = FragmentName()
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
// receiving the data passed from activity here
val data = arguments!!.getString("data_to_be_passed")
return view
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
}
}
活动\u main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.MainActivity">
<FrameLayout
android:id="@+id/fragment_container"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
如果您熟悉Kotlin,那么您可以通过下面的文章来改进此代码。这可能会对您有所帮助
定义片段
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// create fragment instance
val fragment : FragmentName = FragmentName.newInstance()
// for passing data to fragment
val bundle = Bundle()
bundle.putString("data_to_be_passed", DATA)
fragment.arguments = bundle
// check is important to prevent activity from attaching the fragment if already its attached
if (savedInstanceState == null) {
supportFragmentManager
.beginTransaction()
.add(R.id.fragment_container, fragment, "fragment_name")
.commit()
}
}
}
}
class FragmentName : Fragment() {
companion object {
fun newInstance() = FragmentName()
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
// receiving the data passed from activity here
val data = arguments!!.getString("data_to_be_passed")
return view
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
}
}
为片段视图fragment_abc.xml创建xml文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView" />
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button" />
</LinearLayout>
在活动中添加框架布局
<FrameLayout
android:id="@+id/your_placeholder"
android:layout_width="match_parent"
android:layout_height="match_parent">
参考:如果您只想将片段用作活动的顶级内容视图,那么您可以使用ft.add(android.R.id.content,newFragment)
。如果片段的容器不是活动的内容视图,则只需要创建自定义布局并设置其id。不必硬编码id,您可以将其作为普通(R.id.myid)进行编辑和引用。我不知道如何做,但请记住,id只需在您需要使用它的范围内是唯一的。id只需在包含布局的当前继承权限内的级别上是唯一的。假设它被包装在一个线性布局中,它只需要在该线性布局中的其他视图中被解压。您可以使用setId(View.NO_ID)然后使用getId()动态创建一个ID来查看它是什么。欢迎使用堆栈溢出!虽然这在理论上可以回答这个问题,但在这里包括答案的基本部分,并提供链接供参考。不要这样做!在创建片段之前或旋转屏幕之后,如果(savedInstanceState==null)
选中,您将有两个片段或片段重新排序。根本不要使用add
方法!仅更换
。或者你会有奇怪的行为。你从哪里得到“backbackstatename”的值?(使用替换功能时)@vikzilla您可以在中找到非常好的答案。简而言之:backStackStateName
字符串是由您定义的。感谢您的回答,这会将片段选项卡添加到整个屏幕中吗?但如何添加到一帧布局或查看寻呼机?
class FragmentName : Fragment() {
companion object {
fun newInstance() = FragmentName()
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
// receiving the data passed from activity here
val data = arguments!!.getString("data_to_be_passed")
return view
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView" />
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button" />
</LinearLayout>
import androidx.fragment.app.Fragment;
public class FooFragment extends Fragment {
// The onCreateView method is called when Fragment should create its View object hierarchy,
// either dynamically or via XML layout inflation.
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle
savedInstanceState) {
// Defines the xml file for the fragment
return inflater.inflate(R.layout.fragment_abc, parent, false);
}
// This event is triggered soon after onCreateView().
// Any view setup should occur here. E.g., view lookups and attaching view listeners.
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
// Setup any handles to view objects here
// EditText etFoo = (EditText) view.findViewById(R.id.etFoo);
}
}
<FrameLayout
android:id="@+id/your_placeholder"
android:layout_width="match_parent"
android:layout_height="match_parent">
protected void setFragment() {
// Begin the transaction
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
// Replace the contents of the container with the new fragment
ft.replace(R.id.fragment_container, new ABCFragment());
// or ft.add(R.id.your_placeholder, new ABCFragment());
// Complete the changes added above
ft.commit();
}