显示/隐藏片段并以编程方式更改可见性属性
Posted
技术标签:
【中文标题】显示/隐藏片段并以编程方式更改可见性属性【英文标题】:Show/Hide Fragments and change the visibility attribute programmatically 【发布时间】:2013-03-09 10:35:53 【问题描述】:这是一个两部分的问题。我所拥有的是一个 3 Fragment 布局,当用户点击另一个片段中的按钮时,动态添加第 3 个 Fragment(FragmentC)。然后,在添加后,第三个片段有一个按钮来最大化/最小化它。
更新:最后为 SOLUTION
问题 1:
我正在尝试更改用作第三个片段 (R.id.fragment_C) 的容器的 FrameLayout 的可见性属性。
代码应该做的是生成另一个片段,该片段最初具有包含 android:visibility = "gone" 的 XML。然后,在点击按钮时添加 Fragment,并且可见性会更改为 VISIBLE。
我知道这之前已经介绍过,但是在尝试了 4 小时后,我决定问我做错了什么。
问题 2:
生成第 3 个片段后,我有一个最小化/最大化按钮,该按钮应该隐藏前 2 个片段并允许第 3 个片段填满屏幕。
问题是使用 .setVisibility(View.GONE) 时,前 2 个片段的视图没有被删除。这之前也有介绍过,但我不知道为什么它在我的代码中不起作用。
到目前为止的代码(对不起,如果它很冗长,但我认为最好为你们包括所有细节):
main_activity.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_
android:layout_
android:paddingLeft="0dp"
android:paddingRight="0dp"
android:orientation="vertical"
>
<FrameLayout
android:id="@+id/fragment_A"
android:layout_
android:layout_
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:background="#CCCCCC"
>
</FrameLayout>
<FrameLayout
android:id="@+id/fragment_B"
android:layout_
android:layout_
android:layout_below="@id/fragment_A"
android:layout_centerHorizontal="true"
android:layout_marginTop="15dp"
android:background="#B4B4B4"
>
</FrameLayout>
<FrameLayout
android:id="@+id/fragment_C"
android:layout_
android:layout_
android:layout_below="@id/fragment_B"
android:layout_centerHorizontal="true"
android:layout_marginTop="0dp"
android:background="#A3A3A3"
android:visibility="gone"
>
</FrameLayout>
</RelativeLayout>
land/main_activity.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_
android:layout_
android:orientation="horizontal"
android:paddingLeft="0dp"
android:paddingRight="0dp" >
<LinearLayout
android:id="@+id/fragments_container"
android:layout_
android:layout_
android:baselineAligned="false" >
<FrameLayout
android:id="@+id/fragment_A"
android:layout_
android:layout_
android:layout_weight="0.5"
android:background="#CCCCCC" >
</FrameLayout>
<FrameLayout
android:id="@id/fragment_B"
android:layout_
android:layout_
android:layout_weight="0.5"
android:background="#B4B4B4"
>
</FrameLayout>
</LinearLayout>
<FrameLayout
android:id="@+id/fragment_C"
android:layout_
android:layout_
android:layout_below="@id/fragment_container"
android:layout_centerHorizontal="true"
android:layout_marginTop="0dp"
android:background="#A3A3A3"
android:visibility="gone" >
</FrameLayout>
</RelativeLayout>
MainActivity.java
package com.example.android.fragments_proto.activity;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import com.example.android.fragments_proto.R;
import com.example.android.fragments_proto.fragment.GMC_DateSelectionFragment;
import com.example.android.fragments_proto.fragment.GMC_ProdUnitSelectionFragment;
public class MainActivity extends FragmentActivity
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
FragmentManager fm = getSupportFragmentManager();
Fragment fragmentA = fm.findFragmentById(R.id.fragment_A);
Fragment fragmentB = fm.findFragmentById(R.id.fragment_B);
if (fragmentA == null)
FragmentTransaction ft = fm.beginTransaction();
ft.add(R.id.fragment_A, new FragmentA());
ft.commit();
if (fragmentB == null)
FragmentTransaction ft = fm.beginTransaction();
ft.add(R.id.fragment_B, new FragmentB());
ft.commit();
现在是第一个 Fragment 的 XML 和 .java 文件。
fragment_A.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_
android:layout_
android:gravity="center_horizontal"
>
<DatePicker
android:id="@+id/datePicker1"
android:layout_
android:layout_ />
</LinearLayout>
FragmentA.java
package com.example.android.fragments_proto.fragment;
import android.app.Activity;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.widget.DatePicker;
import android.widget.Toast;
import com.example.android.fragments_proto.R;
public class FragmentA extends Fragment
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
View view = inflater.inflate(R.layout.fragment_A, container, false);
DatePicker datePicker = (DatePicker) view.findViewById(R.id.datePicker1);
datePicker.setCalendarViewShown(true);
datePicker.setSpinnersShown(false);
datePicker.setOnTouchListener(new OnTouchListener()
@Override
public boolean onTouch(View v, MotionEvent event)
Activity activity = getActivity();
if (activity != null)
Toast.makeText(activity, "You Touched ME!", Toast.LENGTH_SHORT).show();
return false;
);
return view;
现在包含按钮的片段的 XML 和 .java 文件在点击时会在 R.id.fragment_C 中添加内容
fragment_B.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_
android:layout_
>
<LinearLayout
android:orientation="horizontal"
android:layout_
android:layout_
android:layout_weight="0.1"
>
<ListView
android:id="@+id/listView1"
android:layout_
android:layout_
>
</ListView>
</LinearLayout>
<LinearLayout
android:layout_
android:orientation="horizontal"
android:gravity="center"
android:layout_>
<Button
android:id="@+id/button"
android:text="@string/btn_fragment"
android:layout_
android:layout_
/>
</LinearLayout>
</LinearLayout>
FragmentB.java
package com.example.android.fragments_proto.fragment;
import android.app.Activity;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import com.example.android.fragments_proto.R;
public class FragmentB extends Fragment
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
View view = inflater.inflate(R.layout.fragmentB, container, false);
ListView listView = (ListView) view.findViewById(R.id.listView1);
Button button = (Button) view.findViewById(R.id.button);
String[] machines = new String[] "MachineId-001", "MachineId-002", "MachineId-003", "MachineId-004", "MachineId-005", "MachineId-006", "MachineId-007", "MachineId-008";
listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
listView.setAdapter(new ArrayAdapter<String>(getActivity(), android.R.layout.select_dialog_multichoice, machines));
final FrameLayout frameLayout = (FrameLayout) view.findViewById(R.id.fragment_C);
button.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
Activity activity = getActivity();
if (activity != null)
getFragmentManager().beginTransaction().replace(R.id.fragment_C, new FragmentC()).setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE).addToBackStack(null).commit();
frameLayout.setVisibility(View.VISIBLE);
);
return view;
应该添加的 Fragment 的 XML 和 .java 文件。
fragment_C.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_
android:layout_
android:orientation="vertical" >
<LinearLayout
android:layout_
android:orientation="horizontal"
android:gravity="center"
android:layout_>
<Button
android:id="@+id/maximize_button"
android:layout_
android:layout_
android:text="Maximize Me!" />
</LinearLayout>
<TextView
android:id="@+id/text_view"
android:textIsSelectable="true"
android:layout_
android:layout_
android:background="#FF33FF"
/>
</LinearLayout>
FragmentC.java
package com.example.android.fragments_proto.fragment;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import com.example.android.fragments_proto.R;
public class FragmentC extends Fragment
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
View view = inflater.inflate(R.layout.fragment_C, container, false);
TextView textView = (TextView) view.findViewById(R.id.text_view);
final Fragment fragmentA = getFragmentManager().findFragmentById(R.id.fragment_A);
final Fragment fragmentB = getFragmentManager().findFragmentById(R.id.fragment_B);
button.setOnClickListener(new OnClickListener()
public void onClick(View v)
FragmentTransaction ft = getFragmentManager().beginTransaction();
if (fragmentA.isVisible() && fragmentB.isVisible())
ft.hide(fragmentA);
ft.hide(fragmentB);
fragmentA.getView().setVisibility(View.GONE);
fragmentB.getView().setVisibility(View.GONE);
button.setText("Minimize Me!");
ft.addToBackStack(null);
else
ft.show(fragmentA);
ft.show(fragmentB);
fragmentA.getView().setVisibility(View.VISIBLE);
fragmentB.getView().setVisibility(View.VISIBLE);
button.setText("Maximize Me!");
ft.addToBackStack(null);
ft.commit();
);
return view;
感谢Moesio
问题:
我的错误是我试图用
找到一个视图(在 FragmentB.java 中)最终FrameLayout frameLayout = (FrameLayout) view.findViewById(R.id.fragment_C);
这一行返回 null,所以当代码到达应该执行 .setVisibility() 的点时,应用程序会返回。将返回 nullPointerException。
FragmentC.java 也发生了同样的事情(所以我的 2 个问题是相关的)。未删除视图,因为我的 findViewById 为空!
解决方案:
只需使用 getActivity.findViewById(R.id.your_view); 搜索您的视图;
【问题讨论】:
我将您的代码粘贴到本地项目中,我想我找到了“空”的原因。我编辑过可能会回答。阅读下文。 【参考方案1】:在 FragmentB 中,您正在尝试获取不在您的 contentView 上的视图
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
View view = inflater.inflate(R.layout.fragment_b, container, false);
// this is in fragment_b layout
ListView listView = (ListView) view.findViewById(R.id.listView1);
Button button = (Button) view.findViewById(R.id.button);
/* ... */
// ****************************************
// this is NOT in fragment_b layout, which causes null
// ****************************************
final FrameLayout frameLayout = (FrameLayout) view.findViewById(R.id.fragment_C);
/* ... */
试试:
final FrameLayout frameLayout = (FrameLayout) getActivity().getWindow().findViewById(R.id.fragment_C);
而 R.id.fragment_C 被膨胀并设置在 MainActivity 上。
此外,在使用额外的标志之前,我遇到了同样的问题
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
final Fragment fragmentC = new FragmentC();
fragmentTransaction.add(R.id.fragment_C, fragmentC);
fragmentTransaction.commit();
menuIsOn = false;
final View fragmentCView = findViewById(R.id.fragment_C);
final Button btn = (Button) findViewById(R.id.btn);
btnPowers.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
if (!menuIsOn)
fragmentCView.setVisibility(View.VISIBLE);
else
fragmentCView.setVisibility(View.INVISIBLE);
menuIsOn = !menuIsOn;
);
【讨论】:
感谢您的回答。很抱歉问这个问题,但有点不清楚。我必须在单击按钮时添加第三个片段(在我的示例中,只要我不在 XML 中添加可见性属性就可以工作)。问题是当我添加它并点击应该添加我的第三个片段的按钮(参见 FragmentB.java)时,我的可见性属性会生成 java.lang.NullPointerException 并且应用程序崩溃。你的答案应该如何解决这个问题? 我不明白为什么我的代码会生成 NullPointerException。如果您看一下我的 FragmentB.java 示例,我使用的代码与您的非常相似。无法弄清楚差异在哪里以及它如何帮助我的 FragmentB 什么是空?它发生在哪里? 在 FragmentB 中执行 frameLayout.setVisibility(View.VISIBLE);而且我不知道在我的情况下什么是空的。 我认为这与我在嵌套视图上调用 .setVisibility 的事实有关(请参阅 main_activity.xml 中的 FrameLayout)。不过不确定。【参考方案2】:创建片段实例并添加而不是替换
FragA fa= new FragA();
FragB fb= new FragB();
FragC fc= new FragB();
fragmentManager = getSupportFragmentManager();
fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(R.id.fragmnt_container, fa);
fragmentTransaction.add(R.id.fragmnt_container, fb);
fragmentTransaction.add(R.id.fragmnt_container, fc);
fragmentTransaction.show(fa);
fragmentTransaction.hide(fb);
fragmentTransaction.hide(fc);
fragmentTransaction.commit();
假设我们要根据我们的操作隐藏和显示不同的片段
fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.hide(fa);
fragmentTransaction.show(fb);
fragmentTransaction.hide(fc);
fragmentTransaction.commit();
【讨论】:
以上是关于显示/隐藏片段并以编程方式更改可见性属性的主要内容,如果未能解决你的问题,请参考以下文章
在异步任务中更改 onPostexecute 中的可见性设置