FragmentPagerAdapter仅存在于Android.Support.V4.App(而不是Android.App)中。

164

我在Android.App中找不到FragmentPagerAdapter。

我的目标API是14及以上(Android 4.0及以上),因此我不想使用来自Android.Support.V4.App的Fragment,而是想直接使用Android.App.Fragments和相关类。

我只能在Android.Support.V4.App中找到它,但这对我来说不够好,因为我正在尝试使用Android.App.Fragment (而不是Android.Support.V4 .App.Fragment)以及其相关类在Android.App中(而不是Android.Support.V4.App),如果我的pager从支持库继承,那么我的代码将无法编译,因为Android.App和Android.Support.V4 .App之间的类型不匹配。

就像Cannot be cast to android.app.Fragment一样,在针对API 11或更高版本时派生自普通Activity而不是FragmentActivity时,是否有应该使用的“常规”pager(PagerAdapter)类或其他替代FragmentPagerAdapter的东西?

以下是我正在使用的示例代码(它是MonoDroid示例中Support4.sln解决方案中的FragmentPagerSupport.cs文件,该示例可在https://github.com/xamarin/monodroid-samples/tree/master/Support4找到)。

我已注释掉引用Android.Support.V4.App的行,并用引用Android.App的代码替换了它们。我找不到 FramePagerAdapter以外的任何东西,而我真的需要它。

谢谢。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
//using Android.Support.V4.App;
//using Android.Support.V4.View;

namespace Support4
{
    [Activity (Label = "@string/fragment_pager_support")]
    [IntentFilter (new[]{Intent.ActionMain}, Categories = new[]{ "mono.support4demo.sample" })]
    //public class FragmentPagerSupport : FragmentActivity
        public class FragmentPagerSupport : Activity
    {
        const int NUM_ITEMS = 10;
        MyAdapter adapter;
        ViewPager pager;

        protected override void OnCreate (Bundle bundle)
        {
            base.OnCreate (bundle);

            SetContentView(Resource.Layout.fragment_pager);

            //adapter = new MyAdapter(SupportFragmentManager);
                        adapter = new MyAdapter(FragmentManager);

            pager = FindViewById<ViewPager>(Resource.Id.pager);
            pager.Adapter = adapter;

            var button = FindViewById<Button>(Resource.Id.goto_first);
            button.Click += (sender, e) => {
                pager.CurrentItem = 0;  
            };
            button = FindViewById<Button>(Resource.Id.goto_last);
            button.Click += (sender, e) => {
                pager.CurrentItem = NUM_ITEMS - 1;
            };
        }

                // ?????????????????????????????????????????????????
                // - where is FragmentPagerAdapter 
                // ?????????????????????????????????????????????????

        protected class MyAdapter : FragmentPagerAdapter 
        {
            public MyAdapter(FragmentManager fm) : base(fm)
            {
            }

            public override int Count {
                get {
                    return NUM_ITEMS;
                }
            }

            public override Fragment GetItem (int position)
            {
                return new ArrayListFragment(position);
            }


        }

        protected class ArrayListFragment : ListFragment
        {
            int num;

            public ArrayListFragment()
            {
            }

            public ArrayListFragment(int num)
            {
                var args = new Bundle();
                args.PutInt("num", num);
                Arguments = args;
            }

            public override void OnCreate (Bundle p0)
            {
                base.OnCreate (p0);

                num = Arguments != null ? Arguments.GetInt("num") : 1;
            }

            public override View OnCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
            {
                var v = inflater.Inflate(Resource.Layout.fragment_pager_list, container, false);
                var tv = v.FindViewById<TextView>(Resource.Id.text);
                tv.Text = "Fragment #" + num;
                return v;
            }

            public override void OnActivityCreated (Bundle p0)
            {
                base.OnActivityCreated (p0);

                ListAdapter = new ArrayAdapter<string>(Activity, Android.Resource.Layout.SimpleListItem1, Cheeses.cheeseStrings);
            }

            public override void OnListItemClick(ListView l, View v, int position, long id) {
                Console.WriteLine ( "Item clicked: " + id);
            }
        }
    }
}

5
有一个类在android.support.v13.app.FragmentPagerAdapter里。不确定这是否会对你有所帮助,但是...... - PearsonArtPhoto
PearsonArtPhoto不确定,因为在MonoDroid中没有Android.Support.V13.View命名空间。我宁愿根本不使用支持库,但我认为目前还不可能。 - samus
该类概述部分基本上总结了这种困境 - “请注意,此类目前处于早期设计和开发阶段。 API 可能会在后续兼容库的更新中更改,需要更改应用程序源代码才能针对新版本进行编译。” - samus
文档中的另一节摘录来自 http://developer.android.com/tools/extras/support-library.html:“v4 的支持库提供了访问 Android 3.0 及以上版本引入的几个类,以及某些现有类的更新版本,甚至包括当前 Android 平台上不存在的一些 API”。然而,为什么他们会将 Fragment “API” 中如此重要的部分独占在支持库中,而其余部分则存在于外部。也许这是一个疏忽? - samus
@PearsonArtPhoto 是的,那确实解决了问题。感谢您的建议。 - samus
显示剩余2条评论
5个回答

203

有一个位于android.support.v13.app.FragmentPagerAdapter中的组件,可以实现您想要的功能。它是专为非支持片段设计的FragmentPagerAdapter。

Android Studio安装

请添加以下Gradle依赖项

dependencies {
    compile 'com.android.support:support-v13:+'
}

8
在support lib 13中,存在一个问题,即无法使用嵌套片段和getChildFragmentManager()。 - Yar
3
使用compile 'com.android.support:support-v13:21.0.+'来进行Gradle构建。 - cV2
我的Android Studio无法解析import android.support.v13.app.FragmentPagerAdapter;,有什么想法吗?我已经在Gradle中添加了compile 'com.android.support:support-v13:23.1.1' - Muhammad Naderi
1
在我的情况下,support:support-v13support:design 存在冲突。 - Konstantin Konopko
FYI:目前v13包含所有v4的依赖项,因此从依赖项节省的角度来看,没有任何好处。 - Patrick
4
现在在API 27中已经弃用了它,需要再次使用v4版本。那么我们又面临了问题,没有办法使用不支持库的Fragment。 - Morten Holmgaard

16

嗯,你只需要使用来自V13支持库的FragmentPagerAdapter

Android.Support.V13.App.FragmentPagerAdapter

其他所有与Fragment有关的类都可以从“正常”的库/命名空间中使用,除了ViewPager,但这并不是什么大问题。


以下是完整示例(修改自https://github.com/xamarin/monodroid-samples/的“Support4”示例):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Util;
using Android.Views;
using Android.Widget;

using Java.Lang;

using Android.Support.V4.View;
using Fragment = Android.App.Fragment;

namespace Support4
{
    [Activity (Label = "@string/fragment_pager_support")]
    [IntentFilter (new[]{Intent.ActionMain}, Categories = new[]{ "mono.support4demo.sample" })]
    public class FragmentPagerSupport : Activity
    //public class FragmentPagerSupport : FragmentActivity
    {
        const int NUM_ITEMS = 4;

        protected MyAdapter _pagerAdapter;
        protected ViewPager _viewPager;

        protected override void OnCreate (Bundle bundle)
        {
            base.OnCreate (bundle);

            SetContentView(Resource.Layout.fragment_pager);

            List<Fragment> fragments = new List<Fragment>();

            // *** MonoDroid 4.2.7 letter case bug *** make's first letter lower.

            //string typeName = typeof(Fragment1).FullName;
            string typeName = "support4." + typeof(Fragment1).Name;

            fragments.Add(Fragment.Instantiate(this, typeName));
            fragments.Add(Fragment.Instantiate(this, typeName));
            fragments.Add(Fragment.Instantiate(this, typeName));
            fragments.Add(Fragment.Instantiate(this, typeName));

            //adapter = new MyAdapter(SupportFragmentManager);
            _pagerAdapter = new MyAdapter(FragmentManager, fragments);

            _viewPager = FindViewById<ViewPager>(Resource.Id.view_pager);
            _viewPager.Adapter = _pagerAdapter;
        }

        public override bool OnTouchEvent(MotionEvent e)
        {
            return base.OnTouchEvent(e);
        }

        protected class MyAdapter : Android.Support.V13.App.FragmentPagerAdapter
        {
            private List<Fragment> _fragments;

            public override Java.Lang.Object  InstantiateItem(View p0, int p1)
            {
                return base.InstantiateItem(p0, p1);
            }

            public MyAdapter(Android.App.FragmentManager fm)
                : base(fm)
            {

            }

            //public MyAdapter(Android.Support.V4.App.FragmentManager fm, List<Android.Support.V4.App.Fragment> fragments)
            //    : base(fm)
            public MyAdapter(FragmentManager fm, List<Fragment> fragments)
                : base(fm)
            {
                _fragments = fragments;
            }

            public override int Count {
                get {
                    return NUM_ITEMS;
                }
            }

            //public override Android.Support.V4.App.Fragment GetItem(int p0)
            public override Fragment GetItem(int p0)
            {
                return _fragments[p0];
            }

            public override float GetPageWidth(int p0)
            {
                //return base.GetPageWidth(p0);
                //base.GetPageWidth(p0);

                return (float)(0.5f);
            }
        }
    }

    //public class Fragment1 : Android.Support.V4.App.Fragment
    public class Fragment1 : Fragment
    {
        int num;

        private static int _colorIndex = 0;
        private static Android.Graphics.Color[] _colors = new[] { Android.Graphics.Color.Aqua, Android.Graphics.Color.DarkViolet,
        Android.Graphics.Color.Coral, Android.Graphics.Color.Bisque};

        public Fragment1()
        {
        }

        public Fragment1(int num)
        {
            var args = new Bundle();
            args.PutInt("num", num);
            Arguments = args;
        }

        public override void OnCreate(Bundle p0)
        {
            base.OnCreate(p0);

            num = Arguments != null ? Arguments.GetInt("num") : 1;
        }

        public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
        {
            View v = inflater.Inflate(Resource.Layout.aaaaa, container, false);

            TextView tv = v.FindViewById<TextView>(Resource.Id.text);
            tv.Text = "# " + _colorIndex;
            tv.SetBackgroundColor(_colors[_colorIndex++]);

            return v;
        }

        public override void OnActivityCreated(Bundle p0)
        {
            base.OnActivityCreated(p0);
        }
    }
}

<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2010 The Android Open Source Project

     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at

          http://www.apache.org/licenses/LICENSE-2.0

     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     See the License for the specific language governing permissions and
     limitations under the License.
-->

<!-- Top-level content view for the simple fragment sample. -->

<LinearLayout 
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="horizontal" android:padding="4dip"
  android:layout_width="match_parent" android:layout_height="match_parent">
  <!--android:gravity="center_horizontal"-->

  <android.support.v4.view.ViewPager
    android:id="@+id/view_pager"
    android:layout_width="700dip"
    android:layout_height="match_parent"
    android:layout_weight="1"
    android:background="#FFCCFFFF">

    <!--android:layout_width="match_parent"-->
  </android.support.v4.view.ViewPager>

</LinearLayout>

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/screen_container"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

  <TextView android:id="@+id/text"
      android:layout_width="match_parent" android:layout_height="match_parent"
      android:gravity="center_vertical|center_horizontal"
      android:textAppearance="?android:attr/textAppearanceMedium"
      android:text="@string/hello_world"
      android:background="#FF335555"/>

</LinearLayout>

2
在支持库13中,存在一些混乱的问题,即您无法同时使用嵌套片段和getChildFragmentManager()。 - Yar

2

将此依赖项添加到Gradle依赖项中:

compile 'com.android.support:support-v13:+'

并且可以像这样使用android.support.v13.app.FragmentPagerAdapter(我只是简单地修改了安卓工作室中的官方演示项目:文件→新建→新项目→下一步→下一步→选项卡活动→下一步→完成):

import android.app.Fragment;
import android.app.FragmentManager;
import android.support.v13.app.FragmentPagerAdapter;
import com.google.android.gms.maps.MapFragment;

/** A simple FragmentPagerAdapter that returns a MapFragment and a PreferenceFragment. */
public class MainActivityAdapter extends FragmentPagerAdapter {

    private MapFragment mapFragment;
    private PreferencesFragment preferencesFragment;

    public MainActivityAdapter(FragmentManager fm) {
        super(fm);
        mapFragment = MapFragment.newInstance();
        preferencesFragment = new PreferencesFragment();
    }

    @Override
    public int getCount() {
        return 2;
    }

    @Override
    public Fragment getItem(int position) {
        switch (position) {
            case 0:
                return mapFragment;
            case 1:
                return preferencesFragment;
            default:
                return null;
        }
    }
}

0

根据2019年的AndroidX

implementation 'androidx.legacy:legacy-support-v13:1.0.0'
implementation 'androidx.viewpager:viewpager:1.0.0'

-1

我曾经遇到过同样的问题。我的解决方案是从android.support.v4.app.FragmentPagerAdapter中复制代码,然后将导入的Fragment类更改为android.app.Fragment。之后进行其他小的调整以消除所有错误。令我惊讶的是它完美地工作了。 在我看来,这比添加一个你实际上并不需要的支持库要简单。

import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.os.Parcelable;
import android.support.v4.view.PagerAdapter;
import android.view.View;
import android.view.ViewGroup;

/**
 * PagerAdapter for ViewPager that is compatible with android.app.Fragment.
 */
abstract class FragmentPagerAdapter extends PagerAdapter {

    private final FragmentManager mFragmentManager;
    private FragmentTransaction mCurTransaction = null;
    private Fragment mCurrentPrimaryItem = null;

    /**
     * Returns a unique id for the fragment on the given position.
     * For example this can be the view id that is used on the page's fragment.
     * @param position The page index
     * @return An id that is unique with respect to the pages in the adapter.
     */
    abstract long getItemId(int position);

    /**
     * Returns the fragment for the given page index.
     * @param position The page index
     * @return The fragment
     */
    abstract Fragment getItem(int position);

    public FragmentPagerAdapter(FragmentManager fragmentManager) {
        super();
        mFragmentManager = fragmentManager;
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        if (mCurTransaction == null) {
            mCurTransaction = mFragmentManager.beginTransaction();
        }

        final long itemId = getItemId(position);

        // Do we already have this fragment?
        String name = makeFragmentName(container.getId(), itemId);
        Fragment fragment = mFragmentManager.findFragmentByTag(name);
        if (fragment != null) {
            mCurTransaction.attach(fragment);
        } else {
            fragment = getItem(position);
            mCurTransaction.add(container.getId(), fragment,
                    makeFragmentName(container.getId(), itemId));
        }
        if (fragment != mCurrentPrimaryItem) {
            fragment.setMenuVisibility(false);
        }

        return fragment;
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        if (mCurTransaction == null) {
            mCurTransaction = mFragmentManager.beginTransaction();
        }
        mCurTransaction.detach((Fragment) object);
    }

    @SuppressWarnings("ReferenceEquality")
    @Override
    public void setPrimaryItem(ViewGroup container, int position, Object object) {
        Fragment fragment = (Fragment)object;
        if (fragment != mCurrentPrimaryItem) {
            if (mCurrentPrimaryItem != null) {
                mCurrentPrimaryItem.setMenuVisibility(false);
            }
            if (fragment != null) {
                fragment.setMenuVisibility(true);
            }
            mCurrentPrimaryItem = fragment;
        }
    }

    @Override
    public void finishUpdate(ViewGroup container) {
        if (mCurTransaction != null) {
            mCurTransaction.commitAllowingStateLoss();
            mCurTransaction = null;
        }
    }

    @Override
    public boolean isViewFromObject(View view, Object object) {
        return ((Fragment)object).getView() == view;
    }

    @Override
    public Parcelable saveState() {
        return null;
    }

    @Override
    public void restoreState(Parcelable state, ClassLoader loader) {
    }

    private static String makeFragmentName(int viewId, long id) {
        return "android:switcher:" + viewId + ":" + id;
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接