草庐IT

android - 如何在 ViewPager 的开头添加一个页面?

coder 2023-11-20 原文

关于我的申请
我正在开发一个日历应用程序。想要显示带有水平滑动导航的月 View 吗?这意味着无限滚动用户可以按月向右和向左滚动到任何一年的任何日期/月份。我发现 ViewPager 非常适合实现此目的。(我真的不知道还有什么其他使用完整的方法)。通过单击日期单元格,用户可以看到添加到该日期的详细信息或事件(我不知道不想与设备日历链接)。

关于问题
我可以毫无问题地将新页面添加到我的 View 寻呼机的末尾。但是如果用户向左滑动,我需要在我的 ViewPager 的开头添加一个页面。 .当我在开头添加一个页面(索引位置为零)时,这将替换我当前位置为零的页面并且只能添加一页(没有添加新页面我不知道为什么)。在将页面添加到零位置后,当用户向右滑动并到达最后一页强制关闭时,我什至无法将页面添加到 View 寻呼机的末尾并出现错误:

java.lang.IllegalStateException: Can't change tag of fragment MyFragment{40526bb8 #2  id=0x7f070000 android:switcher:2131165184:2}: was android:switcher:2131165184:2 now android:switcher:2131165184:3

简单句
我想知道在 View pager 的开头和结尾添加页面的正确方法是什么?

代码

Activity 和适配器

    public class PageViewActivity extends FragmentActivity {

    ViewPager pager;
    MyPageAdapter pageAdapter;
    ArrayList<Fragment> fragments;

    int page_num = 0;
    int current_page = 1;
    int selected_page = 1;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_page_view);

        pager = (ViewPager) findViewById(R.id.viewpager);

        fragments = getFragments();

        pageAdapter = new MyPageAdapter(getSupportFragmentManager(), pager,
                fragments);

        pager.setAdapter(pageAdapter);
        pager.setCurrentItem(2);
        pager.setOnPageChangeListener(new OnPageChangeListener() {

            @Override
            public void onPageSelected(int arg0) {

                // setting the selected page index
                selected_page = arg0;       
                //calling add page
                addPage();

            }

            @Override
            public void onPageScrolled(int arg0, float arg1, int arg2) {
                // TODO Auto-generated method stub          

            }

            @Override
            public void onPageScrollStateChanged(int arg0) {
                // TODO Auto-generated method stub
            }
        });


    }

    public int addPage() {

        System.out.println("Add page called "+selected_page);
        // checking if selected page is second last and if tru adds new page 
        if (selected_page >= (pageAdapter.getCount() - 1)) {    

            System.out.println("on first condition");

            Fragment new_fragment = MyFragment.newInstance("Added to last  "+ (pageAdapter.getCount() + 1));
            //pageAdapter.fragments.add(pageAdapter.getCount(), new_fragment);
            System.out.println("pageAdapter.getCount()   :  "+pageAdapter.getCount());
            pageAdapter.add(pageAdapter.getCount(), new_fragment);
            current_page = selected_page;           
            pageAdapter.notifyDataSetChanged();
            System.out.println("New page added");
        }else if((selected_page-1)<=0){

            System.out.println("on second condition");

            Fragment new_fragment = MyFragment.newInstance("Added to begning  "+ (pageAdapter.getCount() + 1));         
            pageAdapter.add(0, new_fragment);
            current_page = selected_page;           
            //pageAdapter.notifyDataSetChanged();
        }

        return pageAdapter.getCount();


    }

    private ArrayList<Fragment> getFragments() {

        ArrayList<Fragment> fList = new ArrayList<Fragment>();

        fList.add(MyFragment.newInstance("Fragment 1"));
        fList.add(MyFragment.newInstance("Fragment 2"));
        fList.add(MyFragment.newInstance("Fragment 3"));
        fList.add(MyFragment.newInstance("Fragment 4"));
        fList.add(MyFragment.newInstance("Fragment 5"));

        return fList;
    }

    private class MyPageAdapter extends FragmentPagerAdapter {

        private ArrayList<Fragment> fragments;
        private ViewPager mPager;

        public MyPageAdapter(FragmentManager fm, ViewPager vp,
            ArrayList<Fragment> fragments) {
            super(fm);
            this.fragments = fragments;
            this.mPager = vp;


        }

        public void  add(int position,Fragment f){          
            fragments.add(position, f);
            this.notifyDataSetChanged();
        }


        @Override
        public Fragment getItem(int position) {
            return this.fragments.get(position);
        }

        @Override
        public int getCount() {
            return this.fragments.size();
        }


    }
}

我的 fragment 类

public class MyFragment extends Fragment {
public static final String EXTRA_MESSAGE = "EXTRA_MESSAGE";

public static final MyFragment newInstance(String message)
{
    MyFragment f = new MyFragment();
    Bundle bdl = new Bundle(1);
    bdl.putString(EXTRA_MESSAGE, message);
    f.setArguments(bdl);
    return f;
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, 
    Bundle savedInstanceState) {

    String message = getArguments().getString(EXTRA_MESSAGE);
    View v = inflater.inflate(R.layout.myfragment_layout, container, false);
    TextView messageTextView = (TextView)v.findViewById(R.id.textView);
    messageTextView.setText(message);

    //return null;
    return v;
}


}

最佳答案

我将在这里解释我在我的案例中的做法,我在设置中添加了同样的东西,除了我需要在几天而不是几个月之间左右滑动:

  1. 我设置了一个最小日期和一个最大日期,这将成为日期导航的限制。就我而言,我设置了很大的限制,从 1970 年到 2050 年,以确保我处理足够的时间线。 如果我们举一个更简单的月份示例,比方说 2012 年到 2014 年,这意味着寻呼机中将有 3 年 * 12 个月 = 36 个不同的位置可用。

  2. 当应用程序启动时,默认情况下我的当前 fragment 显示当前日期,对您来说意味着当前月份。所以我在我的应用程序上创建了一个特定的函数来获取我的时间轴内的位置,以获取其中所选日期的位置。如果我们再次使用上面的示例,则位置将因此为 18。

为了给你一个想法,下面是我如何在我的 Activity 中获取当天的位置:

//position in the timeline
todayPosition = Days.daysBetween(new DateTime(MIN_DATE), new DateTime(getTodayDate())).getDays();

daysBetween 是 Joda Time 库中的一个函数,我用它来获取最小日期和所选日期(即时间轴中的位置)之间的天数。

然后在我的 onCreate 函数中,我在 Activity 创建期间以这种方式初始化寻呼机:

pager.setCurrentItem(mApplication.getTodayPosition());

这是适配器,以防它激发您的灵感:

public class MyFragmentPagerAdapter extends FragmentStatePagerAdapter{

private final int todayPosition;
private MyFragment currentFragment;
private final Calendar todayDate;

/** Constructor of the class */
public MyFragmentPagerAdapter(FragmentManager fm, int today_position, Calendar today_date) {
    super(fm);
    todayPosition = today_position;
    todayDate = (Calendar) today_date.clone();
}

/** This method will be invoked when a page is requested to create */
@Override
public Fragment getItem(int arg0) {     
    currentFragment = new MyFragment();
    Bundle data = new Bundle();

    data.putInt("current_page", arg0);
    currentFragment.setArguments(data);
    return currentFragment;
}

/** Returns the number of pages */
@Override
public int getCount() {     
    return MyApplication.TOTAL_NUMBER_OF_DAYS;
}

@Override
public CharSequence getPageTitle(int position) {
    Calendar newDate = (Calendar) todayDate.clone();

    int diffDays = position - todayPosition;
    newDate.add(Calendar.DATE, diffDays);

    return MyApplication.dateTitleFormat.format(newDate.getTime());
}   
}

我不保证这是最好的解决方案,但至少它是有效的。

关于android - 如何在 ViewPager 的开头添加一个页面?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16983697/

有关android - 如何在 ViewPager 的开头添加一个页面?的更多相关文章

  1. ruby - 如何在 Ruby 中顺序创建 PI - 2

    出于纯粹的兴趣,我很好奇如何按顺序创建PI,而不是在过程结果之后生成数字,而是让数字在过程本身生成时显示。如果是这种情况,那么数字可以自行产生,我可以对以前看到的数字实现垃圾收集,从而创建一个无限系列。结果只是在Pi系列之后每秒生成一个数字。这是我通过互联网筛选的结果:这是流行的计算机友好算法,类机器算法:defarccot(x,unity)xpow=unity/xn=1sign=1sum=0loopdoterm=xpow/nbreakifterm==0sum+=sign*(xpow/n)xpow/=x*xn+=2sign=-signendsumenddefcalc_pi(digits

  2. ruby - 我需要将 Bundler 本身添加到 Gemfile 中吗? - 2

    当我使用Bundler时,是否需要在我的Gemfile中将其列为依赖项?毕竟,我的代码中有些地方需要它。例如,当我进行Bundler设置时:require"bundler/setup" 最佳答案 没有。您可以尝试,但首先您必须用鞋带将自己抬离地面。 关于ruby-我需要将Bundler本身添加到Gemfile中吗?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/4758609/

  3. ruby - 如何在 buildr 项目中使用 Ruby 代码? - 2

    如何在buildr项目中使用Ruby?我在很多不同的项目中使用过Ruby、JRuby、Java和Clojure。我目前正在使用我的标准Ruby开发一个模拟应用程序,我想尝试使用Clojure后端(我确实喜欢功能代码)以及JRubygui和测试套件。我还可以看到在未来的不同项目中使用Scala作为后端。我想我要为我的项目尝试一下buildr(http://buildr.apache.org/),但我注意到buildr似乎没有设置为在项目中使用JRuby代码本身!这看起来有点傻,因为该工具旨在统一通用的JVM语言并且是在ruby中构建的。除了将输出的jar包含在一个独特的、仅限ruby​​

  4. ruby - 什么是填充的 Base64 编码字符串以及如何在 ruby​​ 中生成它们? - 2

    我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%

  5. ruby - 使用 Vim Rails,您可以创建一个新的迁移文件并一次性打开它吗? - 2

    使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta

  6. ruby-on-rails - Rails - 一个 View 中的多个模型 - 2

    我需要从一个View访问多个模型。以前,我的links_controller仅用于提供以不同方式排序的链接资源。现在我想包括一个部分(我假设)显示按分数排序的顶级用户(@users=User.all.sort_by(&:score))我知道我可以将此代码插入每个链接操作并从View访问它,但这似乎不是“ruby方式”,我将需要在不久的将来访问更多模型。这可能会变得很脏,是否有针对这种情况的任何技术?注意事项:我认为我的应用程序正朝着单一格式和动态页面内容的方向发展,本质上是一个典型的网络应用程序。我知道before_filter但考虑到我希望应用程序进入的方向,这似乎很麻烦。最终从任何

  7. ruby-on-rails - 渲染另一个 Controller 的 View - 2

    我想要做的是有2个不同的Controller,client和test_client。客户端Controller已经构建,我想创建一个test_clientController,我可以使用它来玩弄客户端的UI并根据需要进行调整。我主要是想绕过我在客户端中内置的验证及其对加载数据的管理Controller的依赖。所以我希望test_clientController加载示例数据集,然后呈现客户端Controller的索引View,以便我可以调整客户端UI。就是这样。我在test_clients索引方法中试过这个:classTestClientdefindexrender:template=>

  8. ruby - 将 Bootstrap Less 添加到 Sinatra - 2

    我有一个ModularSinatra应用程序,我正在尝试将Bootstrap添加到应用程序中。get'/bootstrap/application.css'doless:"bootstrap/bootstrap"end我在views/bootstrap中有所有less文件,包括bootstrap.less。我收到这个错误:Less::ParseErrorat/bootstrap/application.css'reset.less'wasn'tfound.Bootstrap.less的第一行是://CSSReset@import"reset.less";我尝试了所有不同的路径格式,但它

  9. ruby-on-rails - 如何在 ruby​​ 中使用两个参数异步运行 exe? - 2

    exe应该在我打开页面时运行。异步进程需要运行。有什么方法可以在ruby​​中使用两个参数异步运行exe吗?我已经尝试过ruby​​命令-system()、exec()但它正在等待过程完成。我需要用参数启动exe,无需等待进程完成是否有任何ruby​​gems会支持我的问题? 最佳答案 您可以使用Process.spawn和Process.wait2:pid=Process.spawn'your.exe','--option'#Later...pid,status=Process.wait2pid您的程序将作为解释器的子进程执行。除

  10. ruby - 如何在续集中重新加载表模式? - 2

    鉴于我有以下迁移:Sequel.migrationdoupdoalter_table:usersdoadd_column:is_admin,:default=>falseend#SequelrunsaDESCRIBEtablestatement,whenthemodelisloaded.#Atthispoint,itdoesnotknowthatusershaveais_adminflag.#Soitfails.@user=User.find(:email=>"admin@fancy-startup.example")@user.is_admin=true@user.save!ende

随机推荐