我如何添加一个片段到一个活动与编程创建的内容视图

我想添加一个片段,以编程方式实现其布局的活动。我查看了片段文档,但没有很多例子描述我需要什么。下面是我尝试编写的代码类型:

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);
}
}

...

public class ExampleTwoFragment extends Fragment {


@Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container,
Bundle savedInstanceState) {
Button button = new Button(getActivity());
button.setText("Hello There");
return button;
}
}

这段代码编译,但在开始时崩溃,可能是因为我的FragmentTransaction.add()不正确。正确的做法是什么?

536829 次浏览

事实证明,该代码存在不止一个问题。片段不能以这种方式声明,在与活动相同的java文件中,但不能作为公共内部类声明。框架期望片段的构造函数(不带参数)是公共的和可见的。将片段作为一个内部类移动到Activity中,或者为片段创建一个新的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;
}
}
}

以下是我在阅读Tony Wong的评论后得出的结论:

public class DebugExampleTwo extends BaseActivity {


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addFragment(android.R.id.content,
new DebugExampleTwoFragment(),
DebugExampleTwoFragment.FRAGMENT_TAG);
}


}

...

public abstract class BaseActivity extends Activity {


protected void addFragment(@IdRes int containerViewId,
@NonNull Fragment fragment,
@NonNull String fragmentTag) {
getSupportFragmentManager()
.beginTransaction()
.add(containerViewId, fragment, fragmentTag)
.disallowAddToBackStack()
.commit();
}


protected void replaceFragment(@IdRes int containerViewId,
@NonNull Fragment fragment,
@NonNull String fragmentTag,
@Nullable String backStackStateName) {
getSupportFragmentManager()
.beginTransaction()
.replace(containerViewId, fragment, fragmentTag)
.addToBackStack(backStackStateName)
.commit();
}


}

...

public class DebugExampleTwoFragment extends Fragment {


public static final String FRAGMENT_TAG =
BuildConfig.APPLICATION_ID + ".DEBUG_EXAMPLE_TWO_FRAGMENT_TAG";


// ...


}

芬兰湾的科特林

如果你正在使用Kotlin,一定要看看芬兰湾的科特林扩展 by谷歌提供了什么,或者直接写你自己的。

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 ViewCatalogItemActivity extends SingleFragmentActivity {
@Override
public Fragment onCreateFragment() {
return new FragmentWorkShops();
}


}

看完所有的答案后,我想出了一个优雅的方法:

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根视图容器

重要:不要使用替换片段和这里所示的大多数方法一样,除非你不介意在onrecreation过程中丢失片段变量实例状态。

    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();
}
}
要将一个片段添加到一个Activity或FramentActivity中,需要一个 容器。该容器应该是“Framelayout”,它可以是 包含在XML中,或者您可以使用默认容器 例如"android.R.id.content"来删除或替换中的片段 活动。< / p >

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>

对于空气污染指数17或更高版本,View.generateViewId()将解决这个问题。实用程序方法提供了在构建时不使用的惟一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()
}
}


}
}

activity_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>

FragmentName.kt

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)
}


}

如果你熟悉Kotlin中的扩展,那么你可以通过阅读文章来更好地理解这段代码。

这可能对你有帮助

定义片段

为片段视图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>

创建ABCFragment.java

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在您的活动

<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();
}

参考:https://guides.codepath.com/android/creating-and-using-fragments#defining-a-fragment