webentwicklung-frage-antwort-db.com.de

Holen Sie sich beim Scrollen das in der Mitte sichtbare Element von RecycleView

Das ist was ich will:

 enter image description here

Als Bild oben möchte ich eine Mittellinie auf RecycleView zeichnen und dann beim Scrollen das mittlere Element abrufen (sowie nach links oder rechts verschieben).
Hier ist mein Versuch, ein horizontales RecycleView zu zeichnen:

    HorizontalAdapter adapter = new HorizontalAdapter(data);
    LinearLayoutManager layoutManager
            = new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false);
    recycleView.setLayoutManager(layoutManager);
    recycleView.setAdapter(adapter);

Gibt es eine Möglichkeit zu wissen, welcher Artikel in die Mitte von RecycleView verschoben wird? Und wie kann ich RecycleView nur eine Position nach links oder rechts scrollen?

Update: Ich habe versucht, einen Scroll-Listener zu verwenden, um die mittlere Position zu erhalten, aber er funktioniert nicht als Aspekt. 

  @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
            super.onScrolled(recyclerView, dx, dy);
            int firstPos = layoutManager.findFirstVisibleItemPosition();
            int lastPos = layoutManager.findLastVisibleItemPosition();
            int middle = Math.abs(lastPos - firstPos) / 2 + firstPos;

            int selectedPos = -1;
            for (int i = 0; i < adapter.getItemCount(); i++) {
                if (i == middle) {
                    adapter.getItem(i).setSelected(true);
                    selectedPos = i;
                } else {
                    adapter.getItem(i).setSelected(false);
                }
            }

            adapter.notifyDataSetChanged();
        }

Und erhalte das Ergebnis:

 enter image description here

Ich möchte das ausgewählte Element nur ändern (Text in weiße Farbe umwandeln), wenn es auf dem blauen Feld Rect steht.

43
R4j

Ich habe so etwas gemacht. Ich kann genau das tun, was Sie brauchen ... Zunächst einmal: So funktioniert mein Algorithmus enter image description here

Dies ist mein RecyclerView-Adapter

public class DateAdapter extends RecyclerView.Adapter<DateAdapter.DateViewHolder> {
private ArrayList<LabelerDate> dateDataList;


private static final int VIEW_TYPE_PADDING = 1;
private static final int VIEW_TYPE_ITEM = 2;
private int paddingWidthDate = 0;

private int selectedItem = -1;

public DateAdapter(ArrayList<LabelerDate> dateData, int paddingWidthDate) {
    this.dateDataList = dateData;
    this.paddingWidthDate = paddingWidthDate;

}


@Override
public DateViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    if (viewType == VIEW_TYPE_ITEM) {
        final View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_date,
                parent, false);
        return new DateViewHolder(view);
    } else {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_padding,
                parent, false);

        RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) view.getLayoutParams();
        layoutParams.width = paddingWidthDate;
        view.setLayoutParams(layoutParams);
        return new DateViewHolder(view);
    }
}

@Override
public void onBindViewHolder(DateViewHolder holder, int position) {
    LabelerDate labelerDate = dateDataList.get(position);
    if (getItemViewType(position) == VIEW_TYPE_ITEM) {
        if(labelerDate.dateType.equals(BirthDayActivity.DateType.C31))
                holder.tvDate.setText(String.valueOf(labelerDate.valueDate));
                holder.tvDate.setVisibility(View.VISIBLE);
                holder.imgSmall.setVisibility(View.VISIBLE);

        if (position == selectedItem) {
            holder.tvDate.setTextColor(Color.parseColor("#094673"));
            holder.tvDate.setTextSize(35);
            holder.imgSmall.setBackgroundResource(R.color.textviewbold);

        } else {
            holder.tvDate.setTextColor(Color.GRAY);
            holder.tvDate.setTextSize(35);
            holder.imgSmall.setBackgroundResource(R.color.gray);
        }
    }
}

public void setSelecteditem(int selecteditem) {
    this.selectedItem = selecteditem;
    notifyDataSetChanged();
}

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

@Override
public int getItemViewType(int position) {
    LabelerDate labelerDate = dateDataList.get(position);
    if (labelerDate.dateType.equals(BirthDayActivity.DateType.NONE)) {
        return VIEW_TYPE_PADDING;
    }
    return VIEW_TYPE_ITEM;
}


public class DateViewHolder extends RecyclerView.ViewHolder {
    public TextView tvDate;
    public ImageView imgSmall;

    public DateViewHolder(View itemView) {
        super(itemView);
        tvDate = (TextView) itemView.findViewById(R.id.tvNumberDate);
        imgSmall = (ImageView) itemView.findViewById(R.id.small_marked_dob);
    }
}}

Dies ist der wichtigste Algorithmus:

public void getRecyclerviewDate() {
    recyclerViewDate = (RecyclerView) findViewById(R.id.recyclerViewDay);
    ViewTreeObserver vtoDate = recyclerViewDate.getViewTreeObserver();
    vtoDate.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
        @Override
        public boolean onPreDraw() {
            recyclerViewDate.getViewTreeObserver().removeOnPreDrawListener(this);
            finalWidthDate = recyclerViewDate.getMeasuredWidth();
            itemWidthDate = getResources().getDimension(R.dimen.item_dob_width);
            paddingDate = (finalWidthDate - itemWidthDate) / 2;
            firstItemWidthDate = paddingDate ;
            allPixelsDate = 0;

            final LinearLayoutManager dateLayoutManager = new LinearLayoutManager(getApplicationContext());
            dateLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
            recyclerViewDate.setLayoutManager(dateLayoutManager);
            recyclerViewDate.addOnScrollListener(new RecyclerView.OnScrollListener() {
                @Override
                public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                    super.onScrollStateChanged(recyclerView, newState);
                    synchronized (this) {
                         if(newState == RecyclerView.SCROLL_STATE_IDLE){           
                            calculatePositionAndScrollDate(recyclerView);
                        }
                    }

                }

                @Override
                public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                    super.onScrolled(recyclerView, dx, dy);
                    allPixelsDate += dx;
                }
            });
            if (labelerDates == null)
                labelerDates = new ArrayList<>();
            labelerDates.addAll(genLabelerDate(currentMonth, currentYear));
            dateAdapter = new DateAdapter(labelerDates, (int) firstItemWidthDate);
            recyclerViewDate.setAdapter(dateAdapter);
            return true;
        }
    });
}
/* this if most important, if expectedPositionDate < 0 recyclerView will return to nearest item*/

private void calculatePositionAndScrollDate(RecyclerView recyclerView) {
    int expectedPositionDate = Math.round((allPixelsDate + paddingDate - firstItemWidthDate) / itemWidthDate);

    if (expectedPositionDate == -1) {
        expectedPositionDate = 0;
    } else if (expectedPositionDate >= recyclerView.getAdapter().getItemCount() - 2) {
        expectedPositionDate--;
    }
    scrollListToPositionDate(recyclerView, expectedPositionDate);

}
/* this if most important, if expectedPositionDate < 0 recyclerView will return to nearest item*/
private void scrollListToPositionDate(RecyclerView recyclerView, int expectedPositionDate) {
    float targetScrollPosDate = expectedPositionDate * itemWidthDate + firstItemWidthDate - paddingDate;
    float missingPxDate = targetScrollPosDate - allPixelsDate;
    if (missingPxDate != 0) {
        recyclerView.smoothScrollBy((int) missingPxDate, 0);
    }
}
private void setDateValue() {
    int expectedPositionDateColor = Math.round((allPixelsDate + paddingDate - firstItemWidthDate) / itemWidthDate);
    setColorDate = expectedPositionDateColor + 1;
    //set color here
    dateAdapter.setSelecteditem(setColorDate);
}
 @Override
protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
    super.onRestoreInstanceState(savedInstanceState);   
    allPixelsDate = savedInstanceState.getFloat(BUNDLE_LIST_PIXELS_DATE);
    allPixelsDateChanged = savedInstanceState.getFloat(BUNDLE_LIST_PIXELS_DATE_CHANGED);
}

@Override
protected void onSaveInstanceState(@NonNull Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putFloat(BUNDLE_LIST_PIXELS_DATE, allPixelsDate);
    outState.putFloat(BUNDLE_LIST_PIXELS_DATE_CHANGED, allPixelsDateChanged);
}

Und das ist mein Ergebnis: enter image description here

Schauen Sie sich dieses Video an link , dies ist meine App-Demo

44
TranHieu

Manchmal wird der gesamte Beispiel-Codeblock zusammen benötigt, da wir möglicherweise etwas übersehen. Hier ist, was ich habe, fühle mich frei, etwas zu korrigieren, da ich irgendwo einen kleinen Fehler mache. Und ja, diese Antwort ist eine Erweiterung der Antwort von @tranhieu. Danke @tranhieu.

Hauptaktivität.Java

package com.test;

import Android.app.Activity;
import Android.graphics.Color;
import Android.support.annotation.Nullable;
import Android.support.v7.app.AppCompatActivity;
import Android.os.Bundle;
import Android.support.v7.widget.LinearLayoutManager;
import Android.support.v7.widget.RecyclerView;
import Android.util.Log;
import Android.view.LayoutInflater;
import Android.view.View;
import Android.view.ViewGroup;
import Android.view.ViewTreeObserver;
import Android.widget.TextView;

import Java.util.ArrayList;

public class MainActivity extends Activity {

    private static final String TAG = MainActivity.class.getSimpleName();

    public float firstItemWidthDate;
    public float paddingDate;
    public float itemWidthDate;
    public int allPixelsDate;
    public int finalWidthDate;
    private DateAdapter dateAdapter;
    private ArrayList<LabelerDate> labelerDates = new ArrayList<>();

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        getRecyclerviewDate();

    }


    public void getRecyclerviewDate() {
        final RecyclerView recyclerViewDate = (RecyclerView) findViewById(R.id.rv_tasks_date);
        if (recyclerViewDate != null) {
            recyclerViewDate.postDelayed(new Runnable() {
                @Override
                public void run() {
                    setDateValue();
                }
            }, 300);
            recyclerViewDate.postDelayed(new Runnable() {
                @Override
                public void run() {
                    recyclerViewDate.smoothScrollToPosition(dateAdapter.getItemCount()-1);
                    setDateValue();
                }
            }, 5000);
        }
        ViewTreeObserver vtoDate = recyclerViewDate.getViewTreeObserver();
        vtoDate.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {


            @Override
            public boolean onPreDraw() {
                recyclerViewDate.getViewTreeObserver().removeOnPreDrawListener(this);
                finalWidthDate = recyclerViewDate.getMeasuredWidth();
                itemWidthDate = getResources().getDimension(R.dimen.item_dob_width);
                paddingDate = (finalWidthDate - itemWidthDate) / 2;
                firstItemWidthDate = paddingDate;
                allPixelsDate = 0;

                final LinearLayoutManager dateLayoutManager = new LinearLayoutManager(getApplicationContext());
                dateLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
                recyclerViewDate.setLayoutManager(dateLayoutManager);
                recyclerViewDate.addOnScrollListener(new RecyclerView.OnScrollListener() {
                    @Override
                    public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                        super.onScrollStateChanged(recyclerView, newState);
                        synchronized (this) {
                            if (newState == RecyclerView.SCROLL_STATE_IDLE) {
                                calculatePositionAndScrollDate(recyclerView);
                            }
                        }

                    }

                    @Override
                    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                        super.onScrolled(recyclerView, dx, dy);
                        allPixelsDate += dx;
                    }
                });
                if (labelerDates == null) {
                    labelerDates = new ArrayList<>();
                }
                genLabelerDate();
                dateAdapter = new DateAdapter(labelerDates, (int) firstItemWidthDate);
                recyclerViewDate.setAdapter(dateAdapter);
                dateAdapter.setSelecteditem(dateAdapter.getItemCount() - 1);
                return true;
            }
        });
    }

    private void genLabelerDate() {
        for (int i = 0; i < 32; i++) {
            LabelerDate labelerDate = new LabelerDate();
            labelerDate.setNumber(Integer.toString(i));
            labelerDates.add(labelerDate);

            if (i == 0 || i == 31) {
                labelerDate.setType(DateAdapter.VIEW_TYPE_PADDING);
            } else {
                labelerDate.setType(DateAdapter.VIEW_TYPE_ITEM);
            }
        }
    }
/* this if most important, if expectedPositionDate < 0 recyclerView will return to nearest item*/

    private void calculatePositionAndScrollDate(RecyclerView recyclerView) {
        int expectedPositionDate = Math.round((allPixelsDate + paddingDate - firstItemWidthDate) / itemWidthDate);

        if (expectedPositionDate == -1) {
            expectedPositionDate = 0;
        } else if (expectedPositionDate >= recyclerView.getAdapter().getItemCount() - 2) {
            expectedPositionDate--;
        }
        scrollListToPositionDate(recyclerView, expectedPositionDate);

    }

    /* this if most important, if expectedPositionDate < 0 recyclerView will return to nearest item*/
    private void scrollListToPositionDate(RecyclerView recyclerView, int expectedPositionDate) {
        float targetScrollPosDate = expectedPositionDate * itemWidthDate + firstItemWidthDate - paddingDate;
        float missingPxDate = targetScrollPosDate - allPixelsDate;
        if (missingPxDate != 0) {
            recyclerView.smoothScrollBy((int) missingPxDate, 0);
        }
        setDateValue();
    }

    //
    private void setDateValue() {
        int expectedPositionDateColor = Math.round((allPixelsDate + paddingDate - firstItemWidthDate) / itemWidthDate);
        int setColorDate = expectedPositionDateColor + 1;
//        set color here
        dateAdapter.setSelecteditem(setColorDate);
    }


    public class DateAdapter extends RecyclerView.Adapter<DateAdapter.DateViewHolder> {
        private ArrayList<LabelerDate> dateDataList;


        private static final int VIEW_TYPE_PADDING = 1;
        private static final int VIEW_TYPE_ITEM = 2;
        private int paddingWidthDate = 0;

        private int selectedItem = -1;

        public DateAdapter(ArrayList<LabelerDate> dateData, int paddingWidthDate) {
            this.dateDataList = dateData;
            this.paddingWidthDate = paddingWidthDate;

        }


        @Override
        public DateViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            if (viewType == VIEW_TYPE_ITEM) {
                final View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item,
                    parent, false);
                return new DateViewHolder(view);
            } else {
                View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item,
                    parent, false);

                RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) view.getLayoutParams();
                layoutParams.width = paddingWidthDate;
                view.setLayoutParams(layoutParams);
                return new DateViewHolder(view);
            }
        }

        @Override
        public void onBindViewHolder(DateViewHolder holder, int position) {
            LabelerDate labelerDate = dateDataList.get(position);
            if (getItemViewType(position) == VIEW_TYPE_ITEM) {
                holder.tvDate.setText(labelerDate.getNumber());
                holder.tvDate.setVisibility(View.VISIBLE);

                Log.d(TAG, "default " + position + ", selected " + selectedItem);
                if (position == selectedItem) {
                    Log.d(TAG, "center" + position);
                    holder.tvDate.setTextColor(Color.parseColor("#76FF03"));
                    holder.tvDate.setTextSize(35);

                } else {
                    holder.tvDate.setTextColor(Color.WHITE);
                    holder.tvDate.setTextSize(18);
                }
            } else {
                holder.tvDate.setVisibility(View.INVISIBLE);
            }
        }

        public void setSelecteditem(int selecteditem) {
            this.selectedItem = selecteditem;
            notifyDataSetChanged();
        }

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

        @Override
        public int getItemViewType(int position) {
            LabelerDate labelerDate = dateDataList.get(position);
            if (labelerDate.getType() == VIEW_TYPE_PADDING) {
                return VIEW_TYPE_PADDING;
            } else {
                return VIEW_TYPE_ITEM;
            }

        }


        public class DateViewHolder extends RecyclerView.ViewHolder {
            public TextView tvDate;

            public DateViewHolder(View itemView) {
                super(itemView);
                tvDate = (TextView) itemView.findViewById(R.id.txt_date);
            }
        }
    }

    private class LabelerDate {
        private int type;
        private String number;

        public String getNumber() {
            return number;
        }

        public void setNumber(String number) {
            this.number = number;
        }

        public int getType() {
            return type;
        }

        public void setType(int type) {
            this.type = type;
        }
    }
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
              Android:layout_width="match_parent"
              Android:layout_height="match_parent"
              Android:orientation="vertical">

    <FrameLayout
        Android:layout_width="match_parent"
        Android:layout_height="wrap_content">

        <Android.support.v7.widget.RecyclerView
            Android:id="@+id/rv_tasks_date"
            Android:layout_width="match_parent"
            Android:layout_height="48dp" />

        <ImageView
            Android:layout_width="48dp"
            Android:layout_height="48dp"
            Android:layout_gravity="center"
            Android:layout_marginTop="48dp"
            Android:src="@Android:drawable/ic_dialog_info" />
    </FrameLayout>

</LinearLayout>

item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
              Android:orientation="vertical" Android:layout_width="wrap_content"
              Android:layout_height="match_parent">

    <TextView
        Android:id="@+id/txt_date"
        Android:layout_width="@dimen/item_dob_width"
        Android:layout_height="48dp"
        Android:text="32"
        Android:textColor="@Android:color/white"
        Android:background="@Android:color/darker_gray"
        Android:textSize="28sp"
        Android:gravity="center"/>

</LinearLayout>

dimens.xml

<resources>
    <dimen name="item_dob_width">100dp</dimen>
</resources>
10
silentsudo

Ich habe den SnapHelper hier benutzt:

    // init snaphelper        
    SnapHelper snapHelper = new LinearSnapHelper();
    snapHelper.attachToRecyclerView(recyclerView)

    // init layout manager
    LinearLayoutManager layoutManager = new LinearLayoutManager(mainActivity);
    layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
    recyclerView.setLayoutManager(layoutManager);

    // init adapter
    adatper.setSnapHelper(snapHelper);
    adatper.setLayoutManager(layoutManager);

    adatper.initAdapter(new Float((DisplayHelper.getDisplayWidth(mainActivity) / 2) - (fooViewWidth / 2)).intValue());
    recyclerView.setAdapter(adatper);

Wie von TranHieu gesagt, ist die Lösung des Einfügens von 2 Gegenständen für die Polsterung (am Anfang und an den Endpositionen) gut.

Ich mag die Verwendung von ViewTreeObserver nicht, da der Code schlecht lesbar ist. Bei dieser Technik müssen Sie auch das Neuzeichnen der Elemente verwalten, wenn sie wiederverwertet werden.

Wenn Sie benutzerdefinierte Ansichtsklassen verwenden, können Sie deren Breite direkt in diesen Klassen festlegen.

Das ist zum Beispiel meine Padding-Klasse

/**
 * Created by firegloves on 25/09/15.
 */
@EViewGroup(R.layout.view_padding)
public class PaddingView extends FooView {

    Context mCtx;

    public PaddingView(Context context) {
        super(context);
        mCtx = context;
    }


    public void setWidth(int width) {
        setLayoutParams(new LayoutParams(width, ViewGroup.LayoutParams.WRAP_CONTENT));
    }

}

In meinem Adapter speichere ich die gewünschte Breite des Polsterelements, dh (displayWidth/2) - (realItemWidth/2)

Dies ist mein Adapter. Schauen Sie sich keine Methoden an, die nicht mit RecyclerView.Adapter übereinstimmen. Beachten Sie die Methode initAdapter und die Methode onCreateItemView

@EBean
public class FooAdapterRecycler extends RecyclerViewAdapterBase<Foo, FooView> {

    private final int TYPE_PADDING_VIEW = 0;
    private final int TYPE_REAL_VIEW = 1;

    @RootContext
    Context ctx;
    @Bean(Finder.class)
    IFinder Finder;

    SnapHelper snapHelper;
    RecyclerView.LayoutManager layoutManager;

    private int paddingWidth = 0;

    /**
     * preleva i dati dal Finder
     */
    public void initAdapter(int paddingWidth) {

        /*******************************
         * THIS CODE IS THE IMPORTANT ONE
         ******************************/

        this.paddingWidth = paddingWidth;

        // add 1 item for initial space
        mItems = new ArrayList<>();
        Foo foo = new Foo();
        mItems.add(foo);

        // get real items from Finder
        mItems.addAll(Finder.findAll());

        // add 1 item for final space
        mItems = new ArrayList<>();
        Foo foo2 = new Foo();
        mItems.add(foo2);

    }


    @Override
    public int getItemViewType(int position) {
        if (position == 0 || position == getItemCount()-1) {
            return TYPE_PADDING_VIEW;
        } else {
            return TYPE_REAL_VIEW;
        }
    }

    @Override
    protected FooView onCreateItemView(ViewGroup parent, int viewType) {

        /*******************************
         * THIS CODE IS THE IMPORTANT ONE
         ******************************/

        if (viewType == TYPE_PADDING_VIEW) {
            PaddingView view = PaddingView_.build(ctx);
            view.setWidth(paddingWidth);
            return view;
        } else {
            return FooView_.build(ctx);
        }
    }

    public void setSnapHelper(SnapHelper snapHelper) {
        this.snapHelper = snapHelper;
    }

    public void setLayoutManager(RecyclerView.LayoutManager layoutManager) {
        this.layoutManager = layoutManager;
    }
}

Ich verwende die AndroidAnnotations-Bibliothek, die jedoch nicht erforderlich ist

Hoffentlich hilft das

5
firegloves

Wie in der anderen Antwort erwähnt, gibt es keinen direkten Weg, dies zu tun.

So erreichen Sie wahrscheinlich das, was Sie in der Frage beschrieben haben.

  1. Kennen Sie die Anzahl der auf dem Bildschirm angezeigten Elemente.
  2. Wählen Sie das mittlere Element bei jedem Bildlauf der Ansicht programmgesteuert aus.
  3. Behalten Sie ein teilweise transparentes Bild als Überlagerung auf dem mittleren Element der Recyclingübersicht bei. (Sie müssen die Koordinaten basierend auf der Breite der Recycler-Ansicht oder der Bildschirmbreite und der Breite des Overlay-Bildes berechnen, das Sie auswählen möchten.
  4. Aktualisieren Sie den ausgewählten Wert in einer Textansicht unterhalb der Recycling-Ansicht, wenn ein Bildlauf erfolgt.

Die Bildüberlagerungen müssen so platziert werden, dass sie miteinander verbunden und als ein einziges Steuerelement angezeigt werden.

Verwenden Sie für diese Funktion die EcoGallery-Bibliothek: https://github.com/falnatsheh/EcoGallery

1
user3579059

VERWENDEN VON SNAPHELPER - EINE GLATZERE LÖSUNG

Hier ist es eine andere Lösung, die SnapHelper verwendet. Ausgehend von der Antwort von @TranHieu hier:

https://stackoverflow.com/a/34647005/3944251

und die hier von @ sector11 komprimiert:

https://stackoverflow.com/a/38411582/3944251

Ich habe den folgenden Code geschrieben, der in beiden Antworten ebenfalls basiert. Er ist jedoch einfacher und bietet eine einfachere Lösung mit SnapHelper, die in Android Support Library 24.2.0 vorgestellt wird. 

Hier haben Sie die Klasse MainActivity. Der Rest ist mit der Antwort von @ sector11 derselbe.

import Android.graphics.Color;
import Android.os.Bundle;
import Android.support.annotation.Nullable;
import Android.support.v7.app.AppCompatActivity;
import Android.support.v7.widget.LinearLayoutManager;
import Android.support.v7.widget.LinearSnapHelper;
import Android.support.v7.widget.RecyclerView;
import Android.util.Log;
import Android.view.LayoutInflater;
import Android.view.View;
import Android.view.ViewGroup;
import Android.view.ViewTreeObserver;
import Android.widget.TextView;

import Java.util.ArrayList;

public class MainActivity extends AppCompatActivity {

    private static final String TAG = MainActivity.class.getSimpleName();

    public float firstItemWidthDate;
    public float itemWidthDate;
    public int allPixelsDate;
    public int finalWidthDate;
    private DateAdapter dateAdapter;
    private ArrayList<LabelerDate> labelerDates;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        labelerDates = new ArrayList<>();
        getRecyclerviewDate();

    }


    public void getRecyclerviewDate() {
        final RecyclerView recyclerViewDate = (RecyclerView) findViewById(R.id.rv_tasks_date);
        recyclerViewDate.postDelayed(new Runnable() {
            @Override
            public void run() {
                //recyclerViewDate.smoothScrollToPosition(dateAdapter.getItemCount()-1);
                setDateValue();
            }
        }, 300);
        ViewTreeObserver vtoDate = recyclerViewDate.getViewTreeObserver();
        vtoDate.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {

            @Override
            public boolean onPreDraw() {
                recyclerViewDate.getViewTreeObserver().removeOnPreDrawListener(this);
                finalWidthDate = recyclerViewDate.getMeasuredWidth();
                itemWidthDate = getResources().getDimension(R.dimen.item_dob_width);
                firstItemWidthDate = (finalWidthDate - itemWidthDate) / 2;
                allPixelsDate = 0;

                final LinearLayoutManager dateLayoutManager = new LinearLayoutManager(getApplicationContext());
                dateLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
                recyclerViewDate.setLayoutManager(dateLayoutManager);

                /* Create a LinearSnapHelper and attach the recyclerView to it. */
                final LinearSnapHelper snapHelper = new LinearSnapHelper();
                snapHelper.attachToRecyclerView(recyclerViewDate);

                recyclerViewDate.addOnScrollListener(new RecyclerView.OnScrollListener() {
                    @Override
                    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                        allPixelsDate += dx;
                        recyclerView.post(new Runnable() {
                            public void run() {
                                setDateValue();
                            }
                        });
                    }
                });

                genLabelerDate();
                dateAdapter = new DateAdapter(labelerDates, (int) firstItemWidthDate);
                recyclerViewDate.setAdapter(dateAdapter);
                dateAdapter.setSelecteditem(dateAdapter.getItemCount() - 1);
                return true;
            }
        });
    }

    private void genLabelerDate() {
        for (int i = 0; i < 32; i++) {
            LabelerDate labelerDate = new LabelerDate();
            labelerDate.setNumber(Integer.toString(i));
            labelerDates.add(labelerDate);

            if (i == 0 || i == 31) {
                labelerDate.setType(DateAdapter.VIEW_TYPE_PADDING);
            } else {
                labelerDate.setType(DateAdapter.VIEW_TYPE_ITEM);
            }
        }
    }

    //
    private void setDateValue() {
        int expectedPositionDateColor = Math.round(allPixelsDate / itemWidthDate);
        int setColorDate = expectedPositionDateColor + 1;
//        set color here
        dateAdapter.setSelecteditem(setColorDate);
    }


    public class DateAdapter extends RecyclerView.Adapter<DateAdapter.DateViewHolder> {
        private ArrayList<LabelerDate> dateDataList;


        private static final int VIEW_TYPE_PADDING = 1;
        private static final int VIEW_TYPE_ITEM = 2;
        private int paddingWidthDate = 0;

        private int selectedItem = -1;

        public DateAdapter(ArrayList<LabelerDate> dateData, int paddingWidthDate) {
            this.dateDataList = dateData;
            this.paddingWidthDate = paddingWidthDate;

        }


        @Override
        public DateAdapter.DateViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false);
            if (viewType == VIEW_TYPE_PADDING) {
                RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) view.getLayoutParams();
                layoutParams.width = paddingWidthDate;
                view.setLayoutParams(layoutParams);
            }
            return new DateViewHolder(view);
        }

        @Override
        public void onBindViewHolder(DateAdapter.DateViewHolder holder, int position) {
            LabelerDate labelerDate = dateDataList.get(position);
            if (getItemViewType(position) == VIEW_TYPE_ITEM) {
                holder.tvDate.setText(labelerDate.getNumber());
                holder.tvDate.setVisibility(View.VISIBLE);

                Log.d(TAG, "default " + position + ", selected " + selectedItem);
                if (position == selectedItem) {
                    Log.d(TAG, "center" + position);
                    holder.tvDate.setTextColor(Color.parseColor("#76FF03"));
                    holder.tvDate.setTextSize(35);

                } else {
                    holder.tvDate.setTextColor(Color.WHITE);
                    holder.tvDate.setTextSize(18);
                }
            } else {
                holder.tvDate.setVisibility(View.INVISIBLE);
            }
        }

        public void setSelecteditem(int selecteditem) {
            this.selectedItem = selecteditem;
            notifyDataSetChanged();
        }

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

        @Override
        public int getItemViewType(int position) {
            LabelerDate labelerDate = dateDataList.get(position);
            if (labelerDate.getType() == VIEW_TYPE_PADDING) {
                return VIEW_TYPE_PADDING;
            } else {
                return VIEW_TYPE_ITEM;
            }

        }


        public class DateViewHolder extends RecyclerView.ViewHolder {
            public TextView tvDate;

            public DateViewHolder(View itemView) {
                super(itemView);
                tvDate = (TextView) itemView.findViewById(R.id.txt_date);
            }
        }
    }

    private class LabelerDate {
        private int type;
        private String number;

        public String getNumber() {
            return number;
        }

        public void setNumber(String number) {
            this.number = number;
        }

        public int getType() {
            return type;
        }

        public void setType(int type) {
            this.type = type;
        }
    }
}
1
Dionis Beqiraj

Ich habe in meinem Fall einen anderen Ansatz gewählt.

die Deatils finden Sie hier: RecyclerView - Hervorheben des zentralen sichtbaren Elements beim Scrollen1

Meiner Meinung nach ist meine Lösung einfacher als die anderen.

0
eldivino87

Oh Junge. Ich habe fast eine Woche nach dieser Antwort gesucht und dann die Lösung gefunden. Benutzerdefinierte LayoutManagers? ItemDecorator? Nee. 

Hier ist der einfachste Weg, dies zu tun:

<Android.support.v7.widget.RecyclerView
    Android:layout_width="match_parent"
    Android:layout_height="wrap_content"
    Android:layout_gravity="center_horizontal"
    Android:paddingStart="150dp"
    Android:paddingEnd="150dp"
    Android:clipToPadding="false" />

Der kritische Teil ist:

    Android:paddingStart="150dp"
    Android:paddingEnd="150dp"
    Android:clipToPadding="false"

Und weisen Sie dann einfach SnapHelper Ihrer RecylcerView zu:

val snapHelper = LinearSnapHelper()
snapHelper.attachToRecyclerView(recyclerView)

Das ist es. Die einfachste und perfekteste Lösung für das Problem

0
egorikem

Wenn jemand nach einer allgemeineren Implementierung sucht, basiert mein Code auf den Antworten dieses Threads:

Fügen Sie die CenterLinearSnapHelper hinzu

public class CenterLinearSnapHelper extends LinearSnapHelper {

    //Constants
    public static final String TAG = CenterLinearSnapHelper.class.getSimpleName();

    //Attributes
    private Context context;
    private float itemWidth;
    private OnPaddingComputationListener listener;

    //Constructors

    /**
     * A linear snap helper which helps centering the items in a recyclerview.
     *
     * @param itemWidth The (fixed) width of a child view in pixels.
     */
    public CenterLinearSnapHelper(float itemWidth) {
        this.itemWidth = itemWidth;
    }

    public void attachToRecyclerView(@Nullable RecyclerView recyclerView,
                                     @NonNull OnPaddingComputationListener listener) throws IllegalStateException {
        this.listener = listener;

        //Calculates the padding for the first and end item
        calculatePadding(recyclerView);

        //Create a LinearSnapHelper and attach the recyclerView to it.
        attachToRecyclerView(recyclerView);
    }

    public float getItemWidth() {
        return itemWidth;
    }

    private void calculatePadding(RecyclerView recyclerView) {
        if (recyclerView == null)
            return;

        ViewTreeObserver observer = recyclerView.getViewTreeObserver();
        observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {

            @Override
            public boolean onPreDraw() {
                recyclerView.getViewTreeObserver().removeOnPreDrawListener(this);
                int finalWidth = recyclerView.getMeasuredWidth();
                float padding = (finalWidth - itemWidth) / 2;
                listener.onPadding(padding, finalWidth);
                return true;
            }
        });
    }

    public interface OnPaddingComputationListener {
        void onPadding(float padding, int finalWidth);
    }

}

In Ihrer Aktivität/Fragment, in der Sie Ihre RecyclerView erstellen:

float itemWidth = getResources().getDimension(R.dimen.favorite_room_width);
CenterLinearSnapHelper snapHelper = new CenterLinearSnapHelper(itemWidth);
snapHelper.attachToRecyclerView(binding.listFavorites, (padding, finalWidth) -> {
    //Set the adapter
    roomAdapter = new RoomAdapter(requireContext(), rooms);
    roomAdapter.addPaddingItems((int) padding);
    roomAdapter.setOnToggleClickListener(FavoritesFragment.this);
    binding.listFavorites.setAdapter(roomAdapter);
});

In Ihrem Adapter:

public void addPaddingItems(int padding) {
    if (padding < 0)
        throw new IllegalStateException("Padding cannot be smaller than 0");

    this.padding = padding;
    //Add 2 new items as the first and last
    //NOTE: If you update your existing dataset (e.g add new items), you should redo the calculation!
    rooms.add(0, new Room("First"));
    rooms.add(rooms.size(), new Room("Last"));
}


@Override
public int getItemViewType(int position) {
    if (padding >= 0 && (position == 0 || position == rooms.size() - 1)) {
        return VIEW_TYPE_PADDING;
    }

    return VIEW_TYPE_ITEM;
}

@NonNull
@Override
public RoomViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    ViewFavoriteRoomBinding binding = DataBindingUtil.inflate(inflater, R.layout.view_favorite_room, parent, false);

    if (viewType == VIEW_TYPE_PADDING) {
        RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) binding.getRoot().getLayoutParams();
        layoutParams.width = padding;
        binding.getRoot().setLayoutParams(layoutParams);
    }

    RoomViewHolder viewHolder = new RoomViewHolder(context, binding, onToggleClickListener);
    viewHolder.getRecyclerView().setRecycledViewPool(viewPool);
    return viewHolder;
}
0
Verhelst

Ich glaube nicht, dass es einen direkten Ansatz gibt, um dies zu erreichen. Sie können es versuchen - 

listView.setOnScrollListener (Listener);

@Überfahren

public void onScroll(AbsListView view, int firstVisibleItem,int visibleItemCount, int totalItemCount) {
    int firstVisibleRow = listView.getFirstVisiblePosition();
    int lastVisibleRow = listView.getLastVisiblePosition();
    int count - ((int*)count/2;
    int middle = listview.getChildAt(count - ((int)count/2));
    }
}

sie können diese Antwort auch anweisen https://stackoverflow.com/a/13134100/1320616https://stackoverflow.com/a/19205940/1320616

0
Ankit Aggarwal

Zuerst brauchte ich etwas Ähnliches, nicht das hier. Ich konnte die @TranHieu-Lösung jedoch an meine Bedürfnisse anpassen, also stimmte ich seiner Lösung zu.

Ich wollte eine horizontale Recyclingansicht im Vollbildmodus erstellen, die scrollPosition nach der Aktualisierung durch sroll auf mostVisibleItem aktualisiert.

konfiguration:

private void setUpScrolling() {
    mRecyclerVIew.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
        @Override
        public boolean onPreDraw() {
            mRecyclerVIew.getViewTreeObserver().removeOnPreDrawListener(this);
            CustomScrollListener listener = (CustomScrollListener) mScrollListener;
            listener.width = mRecyclerVIew.getMeasuredWidth();
            listener.dx = 0;
            return true;
        }
    });
}

hörer:

private class CustomScrollListener extends OnScrollListener {
    private int mLastDx = 0;
    int width = 0;
    int dx = 0;

    @Override
    public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
        if (newState == RecyclerView.SCROLL_STATE_IDLE) {
            if (mLastDx != dx) {
                scrollToMostVisibleItem();
            } else {
                dx = 0;
                mLastDx = 0;
            }
        }
        super.onScrollStateChanged(recyclerView, newState);
    }

    @Override
    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
        super.onScrolled(recyclerView, dx, dy);
        this.dx += dx;
    }

    private void scrollToMostVisibleItem() {
        int direction = (dx > 0) ? 1 : -1;
        dx = Math.abs(dx);
        int shiftCount = Math.round(dx / width);
        int pixelShift = dx % width;
        if (pixelShift > width / 2) {
            shiftCount++;
        }

        float targetScrollPixels = shiftCount * width;
        float finalScrollPixels = (targetScrollPixels - dx) * direction;
        if (finalScrollPixels != 0) {
            mRecyclerVIew.smoothScrollBy((int) finalScrollPixels, 0);
            mLastDx = (int) finalScrollPixels;
            dx = 0;
        }
    }
}
0
ThinkDeep