не может получить ScrollView из ViewPager2 в OnPageChangeCallBack - PullRequest
0 голосов
/ 01 августа 2020

У меня ViewPager2 содержит ScrollView. В чем проблема, когда я пытаюсь получить ScrollView текущей страницы в onPageSelected (), это не работает. Здесь я хотел бы установить предыдущий scrollY для ScrollView, когда пользователь вернется к выбранной странице. (потому что scrollY по какой-то причине сбрасывается до этого) Мой код ниже.

ViewPagerAdapter. java (отредактировано)

public class ViewPagerAdapter extends RecyclerView.Adapter<ViewPagerAdapter.ViewHolder> {
    private LayoutInflater mInflater;
    private List<String> mText;
    private ViewPager2 pager2;
    MainActivity main;

    public ViewPagerAdapter(Context context, List<String> data, ViewPager2 pager2, MainActivity main){
        this.mInflater = LayoutInflater.from(context);
        this.mText = data;
        this.pager2 = pager2;
        this.main = main;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType){
        View view = mInflater.inflate(R.layout.tab_scroll_item, parent, false);
        return new ViewPagerAdapter.ViewHolder(view);
    }
    
    @Override
    public void onBindViewHolder(final ViewPagerAdapter.ViewHolder holder, int position){
        holder.scrollView.setTag("scv_tab" + position);
        holder.scrollView.setOnScrollChangeListener(new View.OnScrollChangeListener() {
            @Override
            public void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
                if(scrollY != 0) {
                    main.setScrollY(scrollY, getPosition());
                }
                System.out.println("onScrollChanged : " + scrollY);
            }
        });

        holder.textView.setEnabled(false);
        holder.textView.setEnabled(true);
        holder.textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, applyTextSize());
        holder.textView.setText(mText.get(position));
        holder.textView.setTag("tv_tab" + position);
    }

    @Override
    public int getItemCount(){
        return mText.size();
    }

    protected int getPosition(){
        return pager2.getCurrentItem();
    }

    public class ViewHolder extends RecyclerView.ViewHolder{
        ScrollView scrollView;
        TextView textView;

        public ViewHolder(View itemView){
            super(itemView);
            scrollView = itemView.findViewById(R.id.tab_scroll);
            textView = itemView.findViewById(R.id.tab_textview);
        }
    }

[ОТКЛЮЧЕНО ] onBindViewHolder

@Override
    public void onBindViewHolder(final ViewPagerAdapter.ViewHolder holder, final int position){
        holder.scrollView.setTag("scv_tab" + position);
        holder.scrollView.setOnScrollChangeListener(new View.OnScrollChangeListener() {
            @Override
            public void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
                if(scrollY != 0) {
                    main.storeScrollY(scrollY, position);
                }
                System.out.println("onScrollChanged : " + scrollY);
            }
        });
        int y = main.retrieveScrollY(position);
        holder.scrollView.setScrollY(y);

        holder.textView.setEnabled(false);
        holder.textView.setEnabled(true);
        holder.textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, applyTextSize());
        holder.textView.setText(mText.get(position));
        holder.textView.setTag("tv_tab" + position);
    }

MainActivity. java

@Override
    protected void onCreate(Bundle savedInstanceState) {
        setTheme(R.style.AppTheme);
        super.onCreate(savedInstanceState);
  ...

    mPager2.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
            @Override
            public void onPageSelected(int position) {
                super.onPageSelected(position);
                if(!searchView.isIconified()){
                    searchView.setIconified(true);
                }

                if(highlightModel.getHighlitedOrNot(position)){
                    searchText.deleteTextHighlight(position);
                    highlightModel.setHighlitedOrNot(position, false);
                }

                int positionY[] = getScrollFromViewModel();
                ScrollView sv = findScrollView();            // HERE IS THE PROBLEM
                if(sv != null) {
                    sv.setScrollY(positionY[position]);
                }else{
                    System.out.println("sv is null");       // ALWAYS SHOWS NULL
                }
            }
        });
  ...

        searchView = (SearchView) findViewById(R.id.searchview);
        searchView.setOnSearchClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v){
                fab.setVisibility(View.VISIBLE);
                fab.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        
                        int actualResult = searchText.scrollToHighlightedWord(findTextView()
                                , findScrollView()                    // here findScrollView() works perfectly.
                                , searchResultIndex);
                        if(actualResult == (searchResultIndex + 1)) {
                            ++searchResultIndex;
                        }else if(actualResult == searchResultIndex){
                            showToastAtMain("last word");
                        }else{
                            forOnClose();
                        }
                    }
                });
            }
        });

 private ScrollView findScrollView(){                
        ScrollView sv = mPager2.findViewWithTag("scv_tab" + mPager2.getCurrentItem());
        return sv;
    }

tab_scroll_item. xml (отредактировано)

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

    <ScrollView
        android:id="@+id/tab_scroll"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView
            android:id="@+id/tab_textview"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textSize="20sp"
            android:lineSpacingExtra="7dp"
            android:textIsSelectable="true"
            android:paddingStart="9dp"
            android:paddingTop="9dp"
            android:paddingEnd="9dp"/>

    </ScrollView>
</LinearLayout>

Любой совет искренне признателен. Спасибо, что прочитали этот длинный вопрос.

Ответы [ 2 ]

0 голосов
/ 04 августа 2020

Благодаря snachmsm я узнал, что onPageSelected будет вызываться намного раньше, чем рисунок ViewPager2. И я почему-то нашел свое решение с помощью mPager2.postDelayed (). После их добавления здесь НЕТ нулевого ScrollView.

        mPager2.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
            ...

            //Here I added onPageScrollStateChanged() and postDelayed() in it.
            @Override
            public void onPageScrollStateChanged(int state){
                if(state == ViewPager2.SCROLL_STATE_SETTLING){
                    mPager2.postDelayed(new Runnable() {   
                        
                        @Override
                        public void run() {
                            int position = mPager2.getCurrentItem();
                            int y = scrollModel.getPreviousScrollY(position);

                            ScrollView sv = findScrollView();
                            sv.scrollTo(0, y);
                        }
                    }, 50);
                }
            }
        });
    }
0 голосов
/ 01 августа 2020

onPageSelected будет вызываться намного раньше, чем выбранный механизм рисования страницы, перед любыми onCreateViewHolder и onBindViewHolder. Я бы посоветовал вам каким-то образом «вставить» ваши данные на вашу «страницу» (это View или весь Fragment? Имеет большое значение) и в вашем случае установите эту позицию прокрутки внутри onBindViewHolder. Это заставит рендеринг RecyclerView рисовать даже первый кадр в правильной прокручиваемой позиции. Ваш способ, даже если вы подождете некоторое время для рисования RecyclerView, заставит onBindViewHolder нарисовать первый кадр на 0 прокрутке, а ваш метод будет немного прокручиваться в следующих кадрах - это будет видно как какое-то мигание или быстрое- автопрокрутка (я думаю, что это поведение не предназначено)

edit - добавьте правильный метод для настройки прокрутки для вашего Adapter даже до super call

@Override
public void onPageSelected(int position) {
    int positionY[] = getScrollFromViewModel();
    adapter.setScrollForPosition(positionY[position]);
    super.onPageSelected(position);
    ...

для адаптера

private final HashMap<Integer, Integer> scrollYHistory = new HashMap<>();

public void setScrollForPosition(int position, int scrollY){
    scrollYHistory.put(position, scrollY);
}

используйте сохраненное значение scrollY в onBindViewHolder и очистите запись в вашем HashMap

@Override
public void onBindViewHolder(final ViewPagerAdapter.ViewHolder holder, final int position){
    Integer scrollY = scrollYHistory.remove(position);
    if (scrollY == null) scrollYa = 0; // may be null if not stored yet!
    holder.scrollView.setScrollY(scrollY);
    ...

, а также удалите ненужную ссылку на MainActivity main в конструкторе адаптера и переменной внутри, он уже получает Context, и не нужно (не следует) знать, какой Activity его создает

редактировать - расширяющий комментарий:

вместо вызова scrollView.setScrollY прямо внутри onBindViewHolder вы должны сначала настроить свой TextView, затем дождаться его рендеринга и затем прокрутить до нужного положения

@Override
public void onBindViewHolder(final ViewPagerAdapter.ViewHolder holder, final int position){
    ...
    holder.textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, applyTextSize());
    holder.textView.setText(mText.get(position));
    ...
    holder.textView.post(new Runnable(){
        // this will be called after nearest drawing
        @Override
        public void run() {
            Integer scrollY = scrollYHistory.remove(position);
            if (scrollY == null) scrollYa = 0; // may be null if not stored yet!
            holder.scrollView.setScrollY(scrollY);
        }
    });
}
...