Android 如何在 ViewPager 上进行循环滚动?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/21368693/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to do circular scrolling on ViewPager?
提问by portfoliobuilder
I would like to set my ViewPager to do circular scrolling. I want the first page to be able to scroll to page 2 AND the last page. And I would like my last page to scroll to [last page -1] AND the first page. I have made an attempt, although I am not sure when to call the method I have created. There does not seem to be a method in ViewPager that handles this sort of thing, so I created the below.
我想将我的 ViewPager 设置为循环滚动。我希望第一页能够滚动到第 2 页和最后一页。我希望我的最后一页滚动到 [last page -1] 和第一页。我已经尝试过,虽然我不确定何时调用我创建的方法。ViewPager 中似乎没有处理这种事情的方法,所以我创建了下面的方法。
public ViewPagerAdapter(final ViewPager pager, int... pageIDs) {
super();
int actualNoOfIDs = pageIDs.length;
count = actualNoOfIDs + 2;
Log.d(TAG, "actualNoOfIDs: " + actualNoOfIDs +
"count: " + count);
pageIDsArray = new int[count];
for (int i = 0; i < actualNoOfIDs; i++) {
pageIDsArray[ i + 1] = pageIDs[i];
}
pageIDsArray[0] = pageIDs[actualNoOfIDs - 1];
pageIDsArray[count - 1] = pageIDs[0];
Log.d(TAG, "actualNoOfIDs#2: " + actualNoOfIDs +
"count#2: " + count);
pager.setOnPageChangeListener(new OnPageChangeListener() {
@Override
public void onPageSelected(int position) {
int pageCount = getCount();
if (position == 0) {
pager.setCurrentItem(pageCount - 2, false);
} else if (position == pageCount - 1) {
pager.setCurrentItem(1, false);
}
}
@Override
public void onPageScrollStateChanged(int state) {
// TODO Auto-generated method stub
Log.d(TAG, "onPageScrollStateChanged()");
// if (state == ViewPager.SCROLL_STATE_IDLE) {
// int pageCount = getCount();
// int currentItem = pager.getCurrentItem();
// if (currentItem == 0) {
// pager.setCurrentItem(pageCount - 2, false);
// } else if (currentItem == pageCount - 1) {
// pager.setCurrentItem(1, false);
// }
// }
}
@Override
public void onPageScrolled(int position, float positionOffset,
int positionOffsetPixels) {
// TODO Auto-generated method stub
Log.d(TAG, "onPageScrolled()");
}
});
}
My entire code is sort of lengthy, but if it helps I can post it.
我的整个代码有点冗长,但如果有帮助,我可以发布它。
public class ViewPagerAdapter extends PagerAdapter {
public static String TAG = ViewPagerAdapter.class.getSimpleName();
private int count;
private int[] pageIDsArray;
private TextToSpeech btnTTS;
private TtsButton tTSBtn;
String inputTxt;
Context context;
View itemView;
TextView tvNumber; // container for atomic number
TextView tvSymbol; // container for symbol
TextView tvWeight; // container for weight
TextView tvName; // container for name
TextView tvGroup; // container for group
TextView tvPeriod; // container for period
TextView tvBlock; // container for block
TextView tvFamily; // container for family
TextView tvColor; // container for color
TextView tvPhase; // container for phase
TextView tvMelt; // container for melting point
TextView tvBoil; // container for boiling point
TextView tvNeutrons; // container for neutrons
TextView tvProtons; // container for protons
TextView tvElectrons; // container for electrons
TextView tvUrl; // container for electrons
public ViewPagerAdapter(Context context, List<Integer> arrayAtomicNum,
List<String> arrayName, List<String> arraySymbol, List<String> arrayFamily,
List<String> arrayPhase, List<String> arrayColor, List<Integer> arrayGroup,
List<Integer> arrayPeriod, List<String> arrayBlock, List<Integer> arrayProtons,
List<Integer> arrayNeutrons, List<Integer> arrayElectrons, List<Double> arrayWeight,
List<Double> arrayMelt, List<Double> arrayBoil, List<String> arrayUrl) {
this.context = context;
ElementStructure.arrayAtomicNum = arrayAtomicNum;
ElementStructure.arrayName = arrayName;
ElementStructure.arraySymbol = arraySymbol;
ElementStructure.arrayFamily = arrayFamily;
ElementStructure.arrayPhase = arrayPhase;
ElementStructure.arrayColor = arrayColor;
ElementStructure.arrayGroup = arrayGroup;
ElementStructure.arrayPeriod = arrayPeriod;
ElementStructure.arrayBlock = arrayBlock;
ElementStructure.arrayProtons = arrayProtons;
ElementStructure.arrayNeutrons = arrayNeutrons;
ElementStructure.arrayElectrons = arrayElectrons;
ElementStructure.arrayWeight = arrayWeight;
ElementStructure.arrayMelt = arrayMelt;
ElementStructure.arrayBoil = arrayBoil;
ElementStructure.arrayUrl = arrayUrl;
}
public ViewPagerAdapter(final ViewPager pager, int... pageIDs) {
super();
int actualNoOfIDs = pageIDs.length;
count = actualNoOfIDs + 2;
Log.d(TAG, "actualNoOfIDs: " + actualNoOfIDs +
"count: " + count);
pageIDsArray = new int[count];
for (int i = 0; i < actualNoOfIDs; i++) {
pageIDsArray[ i + 1] = pageIDs[i];
}
pageIDsArray[0] = pageIDs[actualNoOfIDs - 1];
pageIDsArray[count - 1] = pageIDs[0];
Log.d(TAG, "actualNoOfIDs#2: " + actualNoOfIDs +
"count#2: " + count);
pager.setOnPageChangeListener(new OnPageChangeListener() {
@Override
public void onPageSelected(int position) {
int pageCount = getCount();
if (position == 0) {
pager.setCurrentItem(pageCount - 2, false);
} else if (position == pageCount - 1) {
pager.setCurrentItem(1, false);
}
}
@Override
public void onPageScrollStateChanged(int state) {
// TODO Auto-generated method stub
Log.d(TAG, "onPageScrollStateChanged()");
// if (state == ViewPager.SCROLL_STATE_IDLE) {
// int pageCount = getCount();
// int currentItem = pager.getCurrentItem();
// if (currentItem == 0) {
// pager.setCurrentItem(pageCount - 2, false);
// } else if (currentItem == pageCount - 1) {
// pager.setCurrentItem(1, false);
// }
// }
}
@Override
public void onPageScrolled(int position, float positionOffset,
int positionOffsetPixels) {
// TODO Auto-generated method stub
Log.d(TAG, "onPageScrolled()");
}
});
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return ElementStructure.arrayAtomicNum.size();
}
@Override
public boolean isViewFromObject(View view, Object object) {
// TODO Auto-generated method stub
return view == ((RelativeLayout) object);
}
@Override
public Object instantiateItem(ViewGroup container, final int position) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
int layoutColorId = ElementStructure.arrayLayoutColor.get(position);
if (layoutColorId == 1) {
itemView = inflater.inflate(R.layout.frame_learn_a, container,
false);
} else if (layoutColorId == 2) {
itemView = inflater.inflate(R.layout.frame_learn_b, container,
false);
} else if (layoutColorId == 3) {
itemView = inflater.inflate(R.layout.frame_learn_c, container,
false);
} else if (layoutColorId == 4) {
itemView = inflater.inflate(R.layout.frame_learn_d, container,
false);
}
Button btnSpeak = (Button)itemView.findViewById(R.id.btnaudio);
btnSpeak.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
inputTxt = ElementStructure.arrayName.get(position);
tTSBtn = new TtsButton(this, inputTxt);
}
});
// atomic number textView
tvNumber = (TextView)itemView.findViewById(R.id.metanumber);
// symbol textView
tvSymbol = (TextView)itemView.findViewById(R.id.metasymbol);
// weight textView
tvWeight = (TextView)itemView.findViewById(R.id.metaweight);
// name textView
tvName = (TextView)itemView.findViewById(R.id.metaname);
// group textView
tvGroup = (TextView)itemView.findViewById(R.id.metagroup);
// period textView
tvPeriod = (TextView)itemView.findViewById(R.id.metaperiod);
// block textView
tvBlock = (TextView)itemView.findViewById(R.id.metablock);
// family textView
tvFamily = (TextView)itemView.findViewById(R.id.metafamily);
// color textView
tvColor = (TextView)itemView.findViewById(R.id.metacolor);
// phase textView
tvPhase = (TextView)itemView.findViewById(R.id.metaphase);
// melting point textView
tvMelt = (TextView)itemView.findViewById(R.id.metamelt);
// boiling point textView
tvBoil = (TextView)itemView.findViewById(R.id.metaboil);
// neutrons textView
tvNeutrons = (TextView)itemView.findViewById(R.id.metaneutrons);
// protons textView
tvProtons = (TextView)itemView.findViewById(R.id.metaprotons);
// electrons textView
tvElectrons = (TextView)itemView.findViewById(R.id.metaelectrons);
// url textView
tvUrl = (TextView)itemView.findViewById(R.id.metaurl);
// capture position and set to the TextViews
tvNumber.setText(String.valueOf(ElementStructure.arrayAtomicNum.get(position)));
tvSymbol.setText(ElementStructure.arraySymbol.get(position));
tvWeight.setText(String.valueOf(ElementStructure.arrayWeight.get(position)));
tvName.setText(ElementStructure.arrayName.get(position));
tvPeriod.setText(String.valueOf(ElementStructure.arrayPeriod.get(position)));
tvBlock.setText(String.valueOf(ElementStructure.arrayBlock.get(position)));
tvFamily.setText(ElementStructure.arrayFamily.get(position));
tvColor.setText(ElementStructure.arrayColor.get(position));
tvPhase.setText(ElementStructure.arrayPhase.get(position));
tvNeutrons.setText(String.valueOf(ElementStructure.arrayNeutrons.get(position)));
tvProtons.setText(String.valueOf(ElementStructure.arrayProtons.get(position)));
tvElectrons.setText(String.valueOf(ElementStructure.arrayElectrons.get(position)));
tvUrl.setText(ElementStructure.arrayUrl.get(position));
// capture position, adjust for 0 value cases
if (ElementStructure.arrayGroup.get(position) == 0) {
tvGroup.setText("n/a");
} else {
tvGroup.setText(String.valueOf(ElementStructure.arrayGroup.get(position)));
}
if (ElementStructure.arrayMelt.get(position) == 0) {
tvMelt.setText("n/a");
} else {
tvMelt.setText(String.valueOf(ElementStructure.arrayMelt.get(position)));
}
if (ElementStructure.arrayBoil.get(position) == 0) {
tvBoil.setText("n/a");
} else {
tvBoil.setText(String.valueOf(ElementStructure.arrayBoil.get(position)));
}
// add fragments to container (ViewPager)
((ViewPager) container).addView(itemView);
return itemView;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
Log.d(TAG, "destroyItem()");
// remove fragments from container (ViewPager)
((ViewPager) container).removeView((RelativeLayout) object);
}
@Override
public void finishUpdate(View container) {
// TODO Auto-generated method stub
Log.d(TAG, "finishUpdate()");
}
@Override
public void restoreState(Parcelable state, ClassLoader loader) {
// TODO Auto-generated method stub
Log.d(TAG, "restoreState()");
}
@Override
public Parcelable saveState() {
// TODO Auto-generated method stub
Log.d(TAG, "saveState()");
return null;
}
@Override
public void startUpdate(View container) {
// TODO Auto-generated method stub
Log.d(TAG, "startUpdate()");
}
public class TtsButton extends Activity implements OnInitListener {
public TtsButton(OnClickListener onClickListener, String inputTxt) {
super();
tTSCheck(inputTxt);
}
private void tTSCheck (String inputTxt) {
int resultCodeCheck = TextToSpeech.Engine.CHECK_VOICE_DATA_PASS;
if (resultCodeCheck == 1) {
btnTTS = new TextToSpeech(context, this);
} else {
Intent installTTSFiles = new Intent(); //missing data, install it
installTTSFiles.setAction(TextToSpeech.Engine.ACTION_INSTALL_TTS_DATA);
startActivity(installTTSFiles);
}
}
@Override
public void onInit(int status) {
// TODO Auto-generated method stub
if(status == TextToSpeech.SUCCESS)
{
Log.i(TAG, "TTS INIT: SUCCESS");
btnTTS.setLanguage(Locale.US);
btnTTS.speak(inputTxt, TextToSpeech.QUEUE_FLUSH, null);
}
else if(status == TextToSpeech.ERROR)
{
Log.e(TAG, "TTS INIT: ERROR");
}
}
@Override
public void onPause() {
if (btnTTS != null) {
btnTTS.stop();
btnTTS.shutdown();
}
super.onPause();
}
} //end embedded class
} //end ViewPagerAdapter
Thanks in advance. I was thinking about trying to use motion gesture, however, I really do not understand why my method won't work so long that I can call it in the correct spot. My initial thought was to call it in "Object instantiateItem(ViewGroup container, final int position)" every time the position changes, and if the conditions were correct. But I'm not sure if that is best.
提前致谢。我正在考虑尝试使用运动手势,但是,我真的不明白为什么我的方法不能工作这么长时间,以至于我可以在正确的位置调用它。我最初的想法是每次位置改变时,如果条件正确,就在“Object instantiateItem(ViewGroup container, final int position)”中调用它。但我不确定这是否是最好的。
采纳答案by portfoliobuilder
Ok, I have an answer. It was actually easier than I expected, but it does take some trickery. First, let me begin with the set up. Lets say, for example, you have three pages (A-B-C) that you are scrolling through in your ViewPager. And you want to set it up so that if you continue scrolling on C (pg. 3), it goes to A (pg. 1) and if you scrolled backwards on A (pg. 1) it goes to C (pg. 3).
好的,我有一个答案。这实际上比我预期的要容易,但确实需要一些技巧。首先,让我从设置开始。例如,假设您在 ViewPager 中滚动浏览了三个页面 (ABC)。并且您想设置它,以便如果您继续在 C(第 3 页)上滚动,它会转到 A(第 1 页),如果您在 A(第 1 页)上向后滚动,它会转到 C(第 3 页) )。
I am not saying my solution is the best, but it works and I do not see any issues. First, you have to create two "fake" pages. The fake pages represent the first and last pages of your ViewPager. The next thing you will need is to set up an onPageChangeListener(), and use the method onPageSelected(). The reason why you need the fake pages is because onPageSelected() only registers after you have moved (swiped). In other words, without this method the end user would have to scroll to page 2 and back to page 1 to receive a hit on page 1, which also means that page 1 would be skipped depending on your code logic.
我并不是说我的解决方案是最好的,但它有效并且我没有看到任何问题。首先,您必须创建两个“假”页面。假页面代表您的 ViewPager 的第一页和最后一页。接下来您需要设置一个 onPageChangeListener(),并使用 onPageSelected() 方法。您需要假页面的原因是因为 onPageSelected() 仅在您移动(滑动)后才注册。换句话说,如果没有这种方法,最终用户将不得不滚动到第 2 页并返回到第 1 页才能接收到第 1 页的点击,这也意味着第 1 页将根据您的代码逻辑被跳过。
The setup is really the entire answer. Once you have your fake pages, it is just a matter of using setCurrentItem() inside the necessary method.
设置实际上是完整的答案。一旦你有了你的假页面,只需在必要的方法中使用 setCurrentItem() 就可以了。
Here is how my code looks. Be sure to place this inside your public Object instantiateItem(final ViewGroup container, final int position) method, just before you return your view inside of your container.
这是我的代码的外观。在将视图返回到容器内之前,请务必将其放置在公共 Object instantiateItem(final ViewGroup container, final int position) 方法中。
((ViewPager) container).setOnPageChangeListener(new OnPageChangeListener() {
@Override
public void onPageSelected(int position) {
Log.d(TAG, "onPageSelected() :: " + "position: " + position);
// skip fake page (first), go to last page
if (position == 0) {
((ViewPager) container).setCurrentItem(118, false);
}
// skip fake page (last), go to first page
if (position == 119) {
((ViewPager) container).setCurrentItem(1, false); //notice how this jumps to position 1, and not position 0. Position 0 is the fake page!
}
}
That's it, it does the trick! The only other thing to do is start your ViewPager on position 1 (which is the second page: fake page = pg 1, my real starting page = pg 2). Now, every time I scroll to the fake page, I redirect it backwards to the last real page. And every time I scroll forward to the last fake page, I redirect it forwards to the real starting page (pg 2).
就是这样,它起作用了!唯一要做的另一件事是在位置 1 上启动您的 ViewPager(这是第二页:假页 = pg 1,我的真实起始页 = pg 2)。现在,每次我滚动到虚假页面时,我都会将其向后重定向到最后一个真实页面。每次我向前滚动到最后一个假页面时,我都会将其重定向到真正的起始页面(第 2 页)。
Also, do not try to put any code in onPageScrollStateChanged. That method is bizarre, it seems that the state value is uncontrollable. It constantly jumps from one state to another. Even without scrolling. That is just a tip I picked up.
另外,不要尝试在 onPageScrollStateChanged 中放置任何代码。那个方法很诡异,好像状态值是不可控的。它不断地从一种状态跳到另一种状态。即使没有滚动。这只是我得到的一个提示。
回答by tobi_b
This is a solution without fake pages and works like a charm:
这是一个没有假页面的解决方案,就像一个魅力:
public class CircularViewPagerHandler implements ViewPager.OnPageChangeListener {
private ViewPager mViewPager;
private int mCurrentPosition;
private int mScrollState;
public CircularViewPagerHandler(final ViewPager viewPager) {
mViewPager = viewPager;
}
@Override
public void onPageSelected(final int position) {
mCurrentPosition = position;
}
@Override
public void onPageScrollStateChanged(final int state) {
handleScrollState(state);
mScrollState = state;
}
private void handleScrollState(final int state) {
if (state == ViewPager.SCROLL_STATE_IDLE && mScrollState == ViewPager.SCROLL_STATE_DRAGGING) {
setNextItemIfNeeded();
}
}
private void setNextItemIfNeeded() {
if (!isScrollStateSettling()) {
handleSetNextItem();
}
}
private boolean isScrollStateSettling() {
return mScrollState == ViewPager.SCROLL_STATE_SETTLING;
}
private void handleSetNextItem() {
final int lastPosition = mViewPager.getAdapter().getCount() - 1;
if(mCurrentPosition == 0) {
mViewPager.setCurrentItem(lastPosition, true);
} else if(mCurrentPosition == lastPosition) {
mViewPager.setCurrentItem(0, true);
}
}
@Override
public void onPageScrolled(final int position, final float positionOffset, final int positionOffsetPixels) {
}
}
You just have to set it to your ViewPager as onPageChangeListener and that's it:
你只需要将它设置为你的 ViewPager 作为 onPageChangeListener ,就是这样:
viewPager.setOnPageChangeListener(new CircularViewPagerHandler(viewPager));
To avoid having this blue shine at the "end" of your ViewPager you should apply this line to your xml where the ViewPager is placed:
为了避免在 ViewPager 的“末尾”出现这种蓝色光芒,您应该将此行应用于放置 ViewPager 的 xml:
android:overScrollMode="never"
回答by Mani Agarwal
I have created the circular viewpager with smooth scroll from last to first in swipe left and first to last during swipe right.
我创建了圆形 viewpager,在向左滑动时从最后到第一个平滑滚动,在向右滑动时从头到尾平滑滚动。
for this add the last page in the starting and the first page to the last:inside addOnPageChangeListener : we have to do some calculation , when we are 0 position then on onPageScrollStateChanged set the current item as the last item and vise-versa.
为此,将起始页中的最后一页和第一页添加到最后一页:在 addOnPageChangeListener 内部:我们必须进行一些计算,当我们处于 0 位置时,在 onPageScrollStateChanged 上将当前项设置为最后一项,反之亦然。
Have a look to the code
看看代码
public class ViewPagerCircular_new extends AppCompatActivity {
ViewPager viewPager;
ArrayList<String> str = new ArrayList<String>();
boolean chageImage = false;
int setPos;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.view_pager_normal);
viewPager = (ViewPager) findViewById(R.id.vf_home_top_pager);
str.add("6"); // added the last page to the frist
str.add("1"); // First item to display in view pager
str.add("2");
str.add("3");
str.add("4");
str.add("5");
str.add("6"); // last item to display in view pager
str.add("1"); // added the first page to the last
ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());
viewPager.setAdapter(adapter);
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener()
{
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels)
{
if (position == str.size() - 1)
{
chageImage = true;
setPos = 1;
} else if (position == 0)
{
chageImage = true;
setPos = str.size() - 2;
} else
{
chageImage = false;
}
}
@Override
public void onPageSelected(int position)
{
}
@Override
public void onPageScrollStateChanged(int state)
{
if (state == ViewPager.SCROLL_STATE_IDLE && chageImage)
{
viewPager.setCurrentItem(setPos, false);
}
}
});
// display the 1st item as current item
viewPager.setCurrentItem(1);
}
// pager adapter
// 寻呼机适配器
public class ViewPagerAdapter extends FragmentStatePagerAdapter
{
public ViewPagerAdapter(FragmentManager fm)
{
super(fm);
}
@Override
public Fragment getItem(int position)
{
PagerFragment fragment = new PagerFragment();
Bundle bundle = new Bundle();
bundle.putString("pos", str.get(position));
fragment.setArguments(bundle);
return fragment;
}
@Override
public int getCount()
{
return str.size();
}
}
// fragment to display in adapter
// 在适配器中显示的片段
public class PagerFragment extends Fragment
{
Bundle bundle;
String pos;
public PagerFragment()
{
}
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
bundle = getArguments();
pos = bundle.getString("pos");
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
TextView textView = new TextView(ViewPagerCircular_new.this);
textView.setGravity(Gravity.CENTER);
textView.setTextSize(25);
textView.setText(pos);
return textView;
}
}
}
}
回答by JH Lin
I slightly modified the answer from @portfoliobuilder. It's very simple.
Setting the current item with no smooth scroll until PageChangeState
to be "0", so it would be very smooth.
我稍微修改了@portfoliobuilder 的答案。这很简单。设置当前项没有平滑滚动直到PageChangeState
为“0”,所以它会非常平滑。
((ViewPager)container).setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
currentPage = position;
}
@Override
public void onPageScrollStateChanged(int state) {
// state equals to 0 means the scroll action is stop
if(state == 0) {
if(currentPage == 0)
((ViewPager)container).setCurrentItem(imageResourceList.size()-2,false);
if(currentPage == imageResourceList.size()-1)
((ViewPager)container).setCurrentItem(1,false);
}
}
});
回答by Richie Shih
This is my solution:
这是我的解决方案:
myViewPager.java
myViewPager.java
public class myViewPager extends PagerAdapter {
public myViewPager (Context context) {
this.context = context;
}
@Override
public int getCount() {
return rank.length+2;
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
// Declare Variables
TextView textViewRank;
//Log.i(TAG, "get position = "+position);
inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View itemView = inflater.inflate(R.layout.viewpager_item, container,
false);
textViewRank= (TextView) itemView.findViewById(R.id.textView1);
if (position == getCount() - 1) {
textViewRank.setText(rank[0]);
} else if (position == 0) {
textViewRank.setText(rank[rank.length-1]);
} else {
textViewRank.setText(rank[position-1]);
}
((ViewPager) container).addView(itemView);
return itemView;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
}
viewpager_item.xml
viewpager_item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="horizontal" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:id="@+id/textView1"/>
</LinearLayout>
MainActivity.java
主活动.java
public class MainActivity extends AppCompatActivity {
private static final String TAG = MainActivity.class.getName();
public static String[] rank;
myViewPager adapter;
private ViewPager viewPager;
private static int currentPage;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
rank = new String[] { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10" };
viewPager = (ViewPager) findViewById(R.id.view_pager);
adapter = new myViewPager(this);
viewPager.setAdapter(adapter);
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageSelected(int position) {
Log.i(TAG, "onPageSelected = "+position);
currentPage = position;
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
// not needed
}
@Override
public void onPageScrollStateChanged(int state) {
if (state == ViewPager.SCROLL_STATE_IDLE) {
int pageCount = rank.length+2;
if (currentPage == pageCount-1){
viewPager.setCurrentItem(1,false);
} else if (currentPage == 0){
viewPager.setCurrentItem(pageCount-2,false);
}
}
}
});
}
}
activity_main.xml
活动_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v4.view.ViewPager
android:id="@+id/view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1" />
</LinearLayout>
Assumed that the array has 10 elements. Then "add" 2 dummy elements, but not really add. When "get_count" function is called, just return size=10+2 elements.
假设数组有 10 个元素。然后“添加”2 个虚拟元素,但不是真正添加。当调用“get_count”函数时,只返回 size=10+2 个元素。
dummy e[0] e[1] e[2] e[3] e[4] e[5] e[6] e[7] e[8] e[9] dummy
虚拟 e[0] e[1] e[2] e[3] e[4] e[5] e[6] e[7] e[8] e[9] 虚拟
In viewPager.addOnPageChangeListener:
在 viewPager.addOnPageChangeListener 中:
when you slide to the last element, viewPager should set the first element as next.
当您滑动到最后一个元素时,viewPager 应该将第一个元素设置为下一个。
if (currentPage == pageCount-1){
viewPager.setCurrentItem(1,false);
}
when you slide to the first element, viewPager should set the last element as next.
当您滑动到第一个元素时,viewPager 应该将最后一个元素设置为下一个。
else if (currentPage == 0){
viewPager.setCurrentItem(pageCount-2,false);
}
In instantiateItem :
在实例化项目中:
if (position == getCount() - 1) {
textViewRank.setText(rank[0]);
} else if (position == 0) {
textViewRank.setText(rank[rank.length-1]);
} else {
textViewRank.setText(rank[position-1]);
}
回答by Mr.Hosseini
its a simple example , important part of listener is on STATE_IDLE detection of cycle end point. so first implement OnPageChangeListener class then on your handler class add this part :
它是一个简单的例子,监听器的重要部分是对循环终点的 STATE_IDLE 检测。所以首先实现 OnPageChangeListener 类然后在你的处理程序类上添加这部分:
@Override
public void onPageScrollStateChanged(int state) {
if (state == ViewPager.SCROLL_STATE_IDLE) {
if (mPreviousPosition == mCurrentPosition && !mIsEndOfCycle) {
if (mCurrentPosition == 0) {
mViewPager.setCurrentItem(getAdapterItemsCount() - 1);
} else {
mViewPager.setCurrentItem(0);
}
mIsEndOfCycle = true;
} else {
mIsEndOfCycle = false;
}
mPreviousPosition = mCurrentPosition;
}
}
回答by D-D
Try this
尝试这个
((ViewPager) container)
.setOnPageChangeListener(new OnPageChangeListener() {
@Override
public void onPageSelected(int position) {
Log.i("TAG", "pos::" + position);
}
@Override
public void onPageScrollStateChanged(int state) {
// TODO Auto-generated method stub
int currentPage = pager.getCurrentItem();
Log.i("TAG", "currentPage::" + currentPage);
Log.i("TAG", "currentState::" + currentState);
Log.i("TAG", "previousState::" + previousState);
if (currentPage == 4 || currentPage == 0) {
previousState = currentState;
currentState = state;
if (previousState == 1 && currentState == 0) {
pager.setCurrentItem(currentPage == 0 ? 4 : 0);
}
}
}
@Override
public void onPageScrolled(int arg0, float arg1,
int arg2) {
// TODO Auto-generated method stub
}
});
return
This should be placed inside
这个应该放在里面
@Override
public Object instantiateItem(final View container, int position) {}
回答by nile.wangyq
I tried @portfoliobuilder's solution, it's great. But there's a tiny problem: when the current item is the head or the tail, if I just click the ViewPager, not drag, the item will change to the tail or the head. And I added a touch listener to the ViewPager to solve the problem.
我尝试了@portfoliobuilder 的解决方案,它很棒。但是有一个小问题:当当前item是head或者tail时,如果我只是点击ViewPager而不是拖拽,item会变成tail或者head。我在 ViewPager 中添加了一个触摸监听器来解决这个问题。
skinPager.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
//Record the x when press down and touch up,
//to judge whether to scroll between head and tail
int x = (int) event.getX();
int y = (int) event.getY();
if(event.getAction() == MotionEvent.ACTION_DOWN)
skinPagerPressX = x;
else if(event.getAction() == MotionEvent.ACTION_UP)
skinPagerUpX = x;
return false;
}
});
The following is the modified function of portfoliobuilder:
以下是portfoliobuilder的修改功能:
private void handleSetNextItem() {
final int lastPosition = skinPager.getAdapter().getCount() - 1;
//Only scroll when dragged
if(mCurrentPosition == 0 && skinPagerUpX > skinPagerPressX) {
skinPager.setCurrentItem(lastPosition, false);
} else if(mCurrentPosition == lastPosition && skinPagerUpX < skinPagerPressX) {
skinPager.setCurrentItem(0, false);
}
}
回答by jinge
The answer of @tobi_b is not totally successful, since it doesn't slide smoothly from the last to the first(At least in my trial). But I was really inspired by his answer.
My solution is when it's time to jump from the fake last to the real first, wait until last scroll finished. Here is my code, it's very simple,
@tobi_b 的答案并不完全成功,因为它没有从最后一个平滑地滑到第一个(至少在我的试验中)。但我真的被他的回答所鼓舞。我的解决方案是什么时候从假最后跳到真第一,等到最后一次滚动完成。这是我的代码,很简单,
private final class MyPageChangeListener implements OnPageChangeListener {
private int currentPosition;
@Override
public void onPageScrollStateChanged(int state) {
if (state == ViewPager.SCROLL_STATE_IDLE) {
if (currentPosition == viewPager.getAdapter().getCount() - 1) {
viewPager.setCurrentItem(1, false);
}
else if (currentPosition == 0) {
viewPager.setCurrentItem(viewPager.getAdapter().getCount() - 2, false);
}
}
}
@Override
public void onPageScrolled(int scrolledPosition, float percent, int pixels) {
//empty
}
@Override
public void onPageSelected(int position) {
currentPosition = position;
}
}
However, this solution is not perfect. It has a little flaw when slide fast from the last to the first. If we slide twice in a very short time, the second slide will invalidate. This problem need to be solved.
然而,这个解决方案并不完美。从最后一个快速滑动到第一个时它有一个小缺陷。如果我们在很短的时间内滑动两次,第二张幻灯片就会失效。这个问题需要解决。
回答by TheHound.developer
Solved the missing of animation while going from right to left on swiping first page to last and vice-versa
解决了从右向左滑动第一页到最后一页时动画丢失的问题,反之亦然
A slight modification in @tobi_b answer,solved my issue. for this add copy of the last page in the starting and the first page to the last.Then just remove the NOT operator from the below method in PagerAdapter.And change setCurrentItem(lastposition,false) to setCurrentItem(lastposition-1,false) and setCurrentItem(0,false) to setCurrentItem(1,false).
@tobi_b 答案稍作修改,解决了我的问题。为此,将起始页中的最后一页和第一页的副本添加到最后一页。然后只需从 PagerAdapter 中的以下方法中删除 NOT 运算符。并将 setCurrentItem(lastposition,false) 更改为 setCurrentItem(lastposition-1,false) 和setCurrentItem(0,false) 到 setCurrentItem(1,false)。
private void setNextItemIfNeeded() {
if (isScrollStateSettling()) {
handleSetNextItem();
}
}
private boolean isScrollStateSettling() {
return mScrollState == ViewPager.SCROLL_STATE_SETTLING;
}
private void handleSetNextItem() {
final int lastPosition = pager.getAdapter().getCount() - 1;
if(mCurrentPosition == 0) {
pager.setCurrentItem(lastPosition-1, false);
} else if(mCurrentPosition == lastPosition) {
pager.setCurrentItem(1, false);
}
}
And in your MainActivity.java dont forget to set the current item as 1. Hoping this will help some.
并且在您的 MainActivity.java 中不要忘记将当前项目设置为 1。希望这会有所帮助。