Это решение работает с .NET Core 2.2. Он использует метод расширения без выделения на ReadOnlySpan
(SplitNext
).
public class Program {
public void MyAnswer() {
long machineId = 0;
long employeeId = 0;
var description = "machineId: 276744, engineId: 59440, employeeId: 4619825";
var span = description.AsSpan();
while (span.Length > 0) {
var entry = span.SplitNext(',');
var key = entry.SplitNext(':').TrimStart(' ');
var value = entry.TrimStart(' ');
if (key.Equals("machineId", StringComparison.Ordinal)) {
long.TryParse(value, out machineId);
}
if (key.Equals("employeeId", StringComparison.Ordinal)) {
long.TryParse(value, out employeeId);
}
}
}
}
public static class Extensions {
public static ReadOnlySpan SplitNext(this ref ReadOnlySpan span, char seperator) {
int pos = span.IndexOf(seperator);
if (pos > -1) {
var part = span.Slice(0, pos);
span = span.Slice(pos + 1);
return part;
} else {
var part = span;
span = span.Slice(span.Length);
return part;
}
}
}
Я сравнил ваш исходный код, существующий ответ и мой ответ через BenchmarkDotnet. Это показывает, что это решение действительно без выделения ресурсов и работает быстрее, чем оригинальная версия:
BenchmarkDotNet=v0.11.4, OS=Windows 10.0.17763.316 (1809/October2018Update/Redstone5)
Intel Core i5-2500K CPU 3.30GHz (Sandy Bridge), 1 CPU, 4 logical and 4 physical cores
.NET Core SDK=2.2.104
[Host] : .NET Core 2.2.2 (CoreCLR 4.6.27317.07, CoreFX 4.6.27318.02), 64bit RyuJIT
DefaultJob : .NET Core 2.2.2 (CoreCLR 4.6.27317.07, CoreFX 4.6.27318.02), 64bit RyuJIT
| Method | Mean | Error | StdDev | Gen 0/1k Op | Gen 1/1k Op | Gen 2/1k Op | Allocated Memory/Op |
|--------- |-----------:|----------:|----------:|------------:|------------:|------------:|--------------------:|
| Original | 1,164.1 ns | 11.606 ns | 10.289 ns | 0.2937 | - | - | 928 B |
| Answer | 460.5 ns | 4.527 ns | 4.234 ns | - | - | - | - |
| MyAnswer | 445.7 ns | 2.578 ns | 2.412 ns | - | - | - | - |
Помимо оптимизации обработки строк, фактическая функция синтаксического анализа также может быть оптимизирована. Это будет более быстрый анализатор длинных строк:
public static long LongParseFast(ReadOnlySpan value) {
long result = 0;
for (int i = 0; i < value.Length; i++) {
result = 10 * result + (value[i] - 48);
}
return result;
}
Если использовать его в моем примере, он удваивает производительность до 216.0 ns
в моих тестах. Конечно, эта функция не может иметь дело с такими вещами, как отрицательные числа, запятые, точки и другие локали. Но если вы в порядке с этим, это, вероятно, так быстро, как вы можете.
Хорошо, у меня есть ответ. Это было на самом деле проще, чем я ожидал, но это требует некоторой хитрости. Во-первых, позвольте мне начать с настройки. Допустим, например, у вас есть три страницы (A-B-C), которые вы просматриваете в ViewPager. И вы хотите настроить его так, чтобы, если вы продолжаете прокручивать на C (стр. 3), он переходит к A (стр. 1), а если вы прокручиваете назад на A (стр. 1), он переходит к C (стр. 3). ).
Я не говорю, что мое решение является лучшим, но оно работает, и я не вижу никаких проблем. Во-первых, вы должны создать две «поддельные» страницы. Поддельные страницы представляют первую и последнюю страницы вашего ViewPager. Следующее, что вам нужно, это настроить onPageChangeListener () и использовать метод onPageSelected (). Причина, по которой вам нужны поддельные страницы, заключается в том, что onPageSelected () регистрируется только после того, как вы переместились (сильно ударили). Другими словами, без этого метода конечный пользователь должен был бы перейти к странице 2 и вернуться к странице 1, чтобы получить попадание на страницу 1, что также означает, что страница 1 будет пропущена в зависимости от логики вашего кода.
Установка действительно весь ответ. После того, как у вас есть поддельные страницы, нужно просто использовать setCurrentItem () внутри необходимого метода.
Вот как выглядит мой код. Обязательно поместите это внутри вашего публичного метода Object instantiateItem (конечный контейнер ViewGroup, конечная позиция int), непосредственно перед возвратом своего представления внутри вашего контейнера.
((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!
}
}
Вот и все, он делает свое дело! Единственное, что нужно сделать - запустить ViewPager с позиции 1 (это вторая страница: поддельная страница = pg 1, моя настоящая стартовая страница = pg 2). Теперь, каждый раз, когда я прокручиваю на поддельную страницу, я перенаправляю ее назад на последнюю реальную страницу. И каждый раз, когда я прокручиваю вперед до последней фальшивой страницы, я перенаправляю ее на настоящую стартовую страницу (стр. 2).
Кроме того, не пытайтесь поместить какой-либо код в onPageScrollStateChanged. Этот метод причудливый, кажется, что значение состояния неуправляемо. Он постоянно прыгает из одного состояния в другое. Даже без прокрутки. Это всего лишь совет, который я подобрал.
Я создал круговую панель просмотра с плавной прокруткой от последнего к первому при пролистывании влево и от первого до последнего при пролистывании вправо.
для этого добавьте последнюю страницу в начальной и первую страницу к последней: внутри addOnPageChangeListener: мы должны сделать некоторые вычисления, когда мы на 0 месте, то на onPageScrollStateChanged установить текущий элемент в качестве последний пункт и наоборот.
Посмотрите код
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);
}
// адаптер пейджера
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();
}
}
// фрагмент для отображения в адаптере
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;
}
}
}
Я немного изменил ответ от @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);
}
}
});
Ответ @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;
}
}
Однако, это решение не идеально. Он имеет небольшой недостаток при быстром скольжении от последнего к первому. Если мы скользим дважды за очень короткое время, второй слайд будет недействительным. Эту проблему нужно решить.
Это простой пример, важной частью слушателя является обнаружение 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;
}
}
Попробуйте это
((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
Это должно быть размещено внутри
@Override
public Object instantiateItem(final View container, int position) {}
Это решение без поддельных страниц и работает как шарм:
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) {
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, false);
} else if(mCurrentPosition == lastPosition) {
mViewPager.setCurrentItem(0, false);
}
}
@Override
public void onPageScrolled(final int position, final float positionOffset, final int positionOffsetPixels) {
}
}
Вы просто должны установить его на свой ViewPager как onPageChangeListener и все:
viewPager.setOnPageChangeListener(new CircularViewPagerHandler(viewPager));
Чтобы избежать этого синего блеска в «конце» вашего ViewPager, вы должны применить эту строку к вашему xml, где находится ViewPager:
android:overScrollMode="never"
Это мое решение:
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
<?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
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
<?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>
Предполагается, что массив состоит из 10 элементов. Затем «добавить» 2 фиктивных элемента, но не добавить. Когда вызывается функция get_count, просто вернуть size = 10 + 2 элемента.
манекен e [0] e [1] e [2] e [3] e [4] e [5] e [6] e [7] e [8] e [9] dummy
В viewPager.addOnPageChangeListener:
при переходе к последнему элементу viewPager должен установить первый элемент следующим.
if (currentPage == pageCount-1){
viewPager.setCurrentItem(1,false);
}
при переходе к первому элементу viewPager должен установить последний элемент следующим.
else if (currentPage == 0){
viewPager.setCurrentItem(pageCount-2,false);
}
InIntiateItem:
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, а не перетаскиваю, элемент изменится на хвост или голову. И я добавил сенсорный слушатель в 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;
}
});
Следующее является модифицированной функцией портфеля:
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);
}
}
Решено отсутствие анимации при перемещении справа налево при перелистывании первой страницы к последней и наоборот
Небольшое изменение в ответе @tobi_b решило мою проблему. для этого добавьте копию последней страницы в начальной и первой страницы в последнюю. Затем просто удалите оператор NOT из метода ниже в PagerAdapter. И замените 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);
}
}
И в вашем MainActivity.java не забудьте установить текущий элемент равным 1. Надеясь, это поможет некоторым.