我想保持这些方法:
setListShown(true);
setListShownNoAnimation(true);
但如果我使用
onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
膨胀的Fragment
与一个自定义风格的布局,前面的方法不能用,并显示此异常:
07-30 20:17:46.937: E/AndroidRuntime(1374): Caused by: java.lang.IllegalStateException: Can't be used with a custom content view
07-30 20:17:46.937: E/AndroidRuntime(1374): at android.support.v4.app.ListFragment.setListShown(ListFragment.java:282)
07-30 20:17:46.937: E/AndroidRuntime(1374): at android.support.v4.app.ListFragment.setListShown(ListFragment.java:258)
因此,可有什么可能的解决方案?
编辑:
该Fragment
用装载机来填充其ListView
从数据库中。 所以这就是为什么我要保留这些方法,在这儿需要他们的原因:
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
mAdapter.swapCursor(data);
if (isResumed()) {
setListShown(true);
} else {
setListShownNoAnimation(true);
}
}
最简单的解决办法是让我自己基于对代码ListFragment
源,也小部件添加进度的布局显示相同的效果。 到现在为止,我会删除那些行,因为我一直在说。 如果我做了修改,我会在这里粘贴。
只需更换原有ListView
与CustomListView
的内布局onCreateView()
为我工作。
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View layout = super.onCreateView(inflater, container,
savedInstanceState);
ListView lv = (ListView) layout.findViewById(android.R.id.list);
ViewGroup parent = (ViewGroup) lv.getParent();
// Remove ListView and add CustomView in its place
int lvIndex = parent.indexOfChild(lv);
parent.removeViewAt(lvIndex);
LinearLayout mLinearLayout = (LinearLayout) inflater.inflate(
R.layout.custom_list, container, false);
parent.addView(mLinearLayout, lvIndex, lv.getLayoutParams());
return layout;
}
我试过这个解决方案,它的工作原理:
在支持ListFragment
源代码表示,
如果你重写此方法与自己的自定义内容,请考虑在布局文件的标准布局android.R.layout,让你继续保留所有ListFragment的标准行为。 特别是,这是目前具有内置的超静定进度状态显示的唯一途径。
所以,我已经采取了list_content.xml并应用到列表我自己的风格:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
style="@style/page_background">
<LinearLayout android:id="@+id/progressContainer"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"
android:gravity="center">
<ProgressBar style="?android:attr/progressBarStyleLarge"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:paddingTop="4dip"
android:singleLine="true" />
</LinearLayout>
<FrameLayout android:id="@+id/listContainer"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView android:id="@android:id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:drawSelectorOnTop="false"
style="@style/rc_listview"/>
<TextView android:id="@android:id/empty"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:textAppearance="?android:attr/textAppearanceLarge" />
</FrameLayout>
</FrameLayout>
再制成固定ListFragment
从支持源代码复制。
- 我改名一些IDS匹配XML文件中的那些。
删除其onCreateView()
public class FixedListFragment extends Fragment { final private Handler mHandler = new Handler(); final private Runnable mRequestFocus = new Runnable() { public void run() { mList.focusableViewAvailable(mList); } }; final private AdapterView.OnItemClickListener mOnClickListener = new AdapterView.OnItemClickListener() { public void onItemClick(AdapterView<?> parent, View v, int position, long id) { onListItemClick((ListView)parent, v, position, id); } }; ListAdapter mAdapter; ListView mList; View mEmptyView; TextView mStandardEmptyView; View mProgressContainer; View mListContainer; CharSequence mEmptyText; boolean mListShown; public FixedListFragment() { } /** * Provide default implementation to return a simple list view. Subclasses * can override to replace with their own layout. If doing so, the * returned view hierarchy <em>must</em> have a ListView whose id * is {@link android.R.id#list android.R.id.list} and can optionally * have a sibling view id {@link android.R.id#empty android.R.id.empty} * that is to be shown when the list is empty. * * <p>If you are overriding this method with your own custom content, * consider including the standard layout {@link android.R.layout#list_content} * in your layout file, so that you continue to retain all of the standard * behavior of ListFragment. In particular, this is currently the only * way to have the built-in indeterminant progress state be shown. */ /** * Attach to list view once the view hierarchy has been created. */ @Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); ensureList(); } /** * Detach from list view. */ public void onDestroyView() { mHandler.removeCallbacks(mRequestFocus); mList = null; mListShown = false; mEmptyView = mProgressContainer = mListContainer = null; mStandardEmptyView = null; super.onDestroyView(); } /** * This method will be called when an item in the list is selected. * Subclasses should override. Subclasses can call * getListView().getItemAtPosition(position) if they need to access the * data associated with the selected item. * * @param l The ListView where the click happened * @param v The view that was clicked within the ListView * @param position The position of the view in the list * @param id The row id of the item that was clicked */ public void onListItemClick(ListView l, View v, int position, long id) { } /** * Provide the cursor for the list view. */ public void setListAdapter(ListAdapter adapter) { boolean hadAdapter = mAdapter != null; mAdapter = adapter; if (mList != null) { mList.setAdapter(adapter); if (!mListShown && !hadAdapter) { // The list was hidden, and previously didn't have an // adapter. It is now time to show it. setListShown(true, getView().getWindowToken() != null); } } } /** * Set the currently selected list item to the specified * position with the adapter's data * * @param position */ public void setSelection(int position) { ensureList(); mList.setSelection(position); } /** * Get the position of the currently selected list item. */ public int getSelectedItemPosition() { ensureList(); return mList.getSelectedItemPosition(); } /** * Get the cursor row ID of the currently selected list item. */ public long getSelectedItemId() { ensureList(); return mList.getSelectedItemId(); } /** * Get the activity's list view widget. */ public ListView getListView() { ensureList(); return mList; } /** * The default content for a ListFragment has a TextView that can * be shown when the list is empty. If you would like to have it * shown, call this method to supply the text it should use. */ public void setEmptyText(CharSequence text) { ensureList(); if (mStandardEmptyView == null) { throw new IllegalStateException("Can't be used with a custom content view"); } mStandardEmptyView.setText(text); if (mEmptyText == null) { mList.setEmptyView(mStandardEmptyView); } mEmptyText = text; } /** * Control whether the list is being displayed. You can make it not * displayed if you are waiting for the initial data to show in it. During * this time an indeterminant progress indicator will be shown instead. * * <p>Applications do not normally need to use this themselves. The default * behavior of ListFragment is to start with the list not being shown, only * showing it once an adapter is given with {@link #setListAdapter(ListAdapter)}. * If the list at that point had not been shown, when it does get shown * it will be do without the user ever seeing the hidden state. * * @param shown If true, the list view is shown; if false, the progress * indicator. The initial value is true. */ public void setListShown(boolean shown) { setListShown(shown, true); } /** * Like {@link #setListShown(boolean)}, but no animation is used when * transitioning from the previous state. */ public void setListShownNoAnimation(boolean shown) { setListShown(shown, false); } /** * Control whether the list is being displayed. You can make it not * displayed if you are waiting for the initial data to show in it. During * this time an indeterminant progress indicator will be shown instead. * * @param shown If true, the list view is shown; if false, the progress * indicator. The initial value is true. * @param animate If true, an animation will be used to transition to the * new state. */ private void setListShown(boolean shown, boolean animate) { ensureList(); if (mProgressContainer == null) { throw new IllegalStateException("Can't be used with a custom content view"); } if (mListShown == shown) { return; } mListShown = shown; if (shown) { if (animate) { mProgressContainer.startAnimation(AnimationUtils.loadAnimation( getActivity(), android.R.anim.fade_out)); mListContainer.startAnimation(AnimationUtils.loadAnimation( getActivity(), android.R.anim.fade_in)); } else { mProgressContainer.clearAnimation(); mListContainer.clearAnimation(); } mProgressContainer.setVisibility(View.GONE); mListContainer.setVisibility(View.VISIBLE); } else { if (animate) { mProgressContainer.startAnimation(AnimationUtils.loadAnimation( getActivity(), android.R.anim.fade_in)); mListContainer.startAnimation(AnimationUtils.loadAnimation( getActivity(), android.R.anim.fade_out)); } else { mProgressContainer.clearAnimation(); mListContainer.clearAnimation(); } mProgressContainer.setVisibility(View.VISIBLE); mListContainer.setVisibility(View.GONE); } } /** * Get the ListAdapter associated with this activity's ListView. */ public ListAdapter getListAdapter() { return mAdapter; } private void ensureList() { if (mList != null) { return; } View root = getView(); if (root == null) { throw new IllegalStateException("Content view not yet created"); } if (root instanceof ListView) { mList = (ListView)root; } else { mStandardEmptyView = (TextView)root.findViewById(android.R.id.empty); if (mStandardEmptyView == null) { mEmptyView = root.findViewById(android.R.id.empty); } else { mStandardEmptyView.setVisibility(View.GONE); } mProgressContainer = root.findViewById(R.id.progressContainer); mListContainer = root.findViewById(R.id.listContainer); View rawListView = root.findViewById(android.R.id.list); if (!(rawListView instanceof ListView)) { if (rawListView == null) { throw new RuntimeException( "Your content must have a ListView whose id attribute is " + "'android.R.id.list'"); } throw new RuntimeException( "Content has view with id attribute 'android.R.id.list' " + "that is not a ListView class"); } mList = (ListView)rawListView; if (mEmptyView != null) { mList.setEmptyView(mEmptyView); } else if (mEmptyText != null) { mStandardEmptyView.setText(mEmptyText); mList.setEmptyView(mStandardEmptyView); } } mListShown = true; mList.setOnItemClickListener(mOnClickListener); if (mAdapter != null) { ListAdapter adapter = mAdapter; mAdapter = null; setListAdapter(adapter); } else { // We are starting without an adapter, so assume we won't // have our data right away and start with the progress indicator. if (mProgressContainer != null) { setListShown(false, false); } } mHandler.post(mRequestFocus); } }
在那之后,一切都完美。 在创建时就在此充气list_content.xml Fragment
。
public View onCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.list_content, container, false);
return view;
}
为我工作,以及另一种解决方案就是把这个线
<include layout="@android:layout/list_content" />
而不是你的ListView。
你能够建立自己的内容,在它的上面或与其他一些看法环绕它。 例如,这里是我的布局看起来像:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="@dimen/default_view_padding"
android:gravity="center"
android:weightSum="4">
<ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/btnCounterBack"
android:src="?attr/ic_previous"
android:background="?android:attr/selectableItemBackground"
android:contentDescription="@null"/>
<TextView
android:id="@+id/tvCounterLevel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="@string/counter_categories"
android:layout_gravity="center"
android:paddingTop="@dimen/default_view_padding"
android:paddingBottom="@dimen/default_view_padding"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:gravity="center"/>
</RelativeLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="center_vertical"
android:background="?attr/dropShadowBackground"
android:orientation="vertical" >
<include layout="@android:layout/list_content" />
</LinearLayout>
setListShown(true);
和setListShownNoAnimation(true);
不受API等级11+的支持包,只提供支持。 你要么必须放弃<= API级别10(坏的选择)的支持或删除线。
如果我理解的文档正确,您不必将它们设置反正,因为true
是默认值