2016-08-23 16 views
10

Chciałbym zaimplementować ekran, na którym mam widok karty zawierający widok RecyclerView.Przewijane CardView z RecyclerView wewnątrz

CardView powinien mieć taką samą wysokość zawartości widoku recyklera, co oznacza, że ​​jeśli w RecyclerView jest niewiele elementów, powinienem zobaczyć dolne rogi i dolny cień karty, ale jeśli RecyclerView ma wiele przedmiotów, Widok karty powinien "przewijać" widok RecyclerView, aby mieć dolne rogi i cień widoku karty na dole okna RecylerView.

Oto co powinno wyglądać, gdy RecyclerView jest na górze: List at top

Gdy użytkownik zaczyna przewijać, górne rogi znikną z RecyclerView przewijania: List during scroll

I wreszcie, gdy użytkownik dojdzie do dolnej części okna RecyclerView, pojawią się dolne rogi i cień CardView: List at end

Od tej pory udało mi się wykonać działające wdrożenie przez umieszczenie RecyclerView wewnątrz CardView i CardView wewnątrz NestedScrollView ale to łamie gest Fling ...

<android.support.design.widget.CoordinatorLayout 
    xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:app="http://schemas.android.com/apk/res-auto" 
    xmlns:tools="http://schemas.android.com/tools" 
    android:clipChildren="false" 
    android:id="@+id/containerLayout" 
    android:layout_height="match_parent" 
    android:layout_width="match_parent" 
    android:orientation="vertical" 
    tools:ignore="MissingPrefix"> 

    <android.support.v4.widget.NestedScrollView 
     android:clipToPadding="false" 
     android:layout_height="match_parent" 
     android:layout_width="match_parent" 
     android:paddingBottom="16dp" 
     android:paddingLeft="85dp" 
     android:paddingRight="85dp" 
     android:paddingTop="16dp"> 

     <android.support.v7.widget.CardView 
      android:layout_height="wrap_content" 
      android:layout_width="match_parent" 
      app:cardBackgroundColor="?android:attr/windowBackground"> 

      <android.support.v7.widget.RecyclerView 
       android:id="@+id/recyclerView" 
       android:layout_height="wrap_content" 
       android:layout_width="match_parent"/> 
     </android.support.v7.widget.CardView> 
    </android.support.v4.widget.NestedScrollView> 
</android.support.design.widget.CoordinatorLayout> 

Czy macie jakieś wskazówki lub pomysł, w jaki sposób mogę realizować taki projekt? Chyba że CoordinatorLayout może mi pomóc, ale nie mogłem znaleźć nic ...

Dziękuję

+1

Mam ten sam problem. 'android: nestedScrollingEnabled =" false "' naprawia gest rzucania, ale interfejs jest bardzo opóźniony, jeśli Twój RecyclerView jest wystarczająco duży. Czy masz jakieś postępy w tej sprawie? – vyndor

+0

@ pdegand59 Myślałem o rozwiązaniu bez ** NestedScrollView **, ale z odbiornikiem przewijania do 'RecyclerView'. Kiedy przewijasz od dołu do góry, 'CardView' przejdzie na twój ekran_; kiedy dojdziesz do końca twoich przedmiotów, pojawi się dół. Można to osiągnąć za pomocą 'cardView.animate() .y (theNewPosition) .setDuration (0) .start()'. To tylko pomysł, nie przetestowałem go na kodzie. – JJ86

+1

Należy pamiętać, że użycie 'RecyclerView' wewnątrz' NestedScrollView' jest jak użycie 'LinearLayout' wewnątrz' ScrollView'. Nie będzie recyklingu, 'RecyclerView' będzie miał wysokość itemHeight * itemCount. Jeśli się tym nie przejmujesz, zamień 'NestedScrollView' na' ScrollView', a otrzymasz gest rzucania. – Oknesif

Odpowiedz

0

Mam propozycję opartą na Constraintlayout którego użyłem wcześniej. Można utworzyć dwa Guideline, aby ustawić początkową i końcową pozycję CardView podczas przewijania. Pozwól mi ilustrują XML do położenia początkowego widoku

<android.support.constraint.ConstraintLayout 
xmlns:android="http://schemas.android.com/apk/res/android" 
xmlns:app="http://schemas.android.com/apk/res-auto" 
xmlns:tools="http://schemas.android.com/tools" 
android:clipChildren="false" 
android:id="@+id/containerLayout" 
android:layout_height="match_parent" 
android:layout_width="match_parent" 
android:orientation="vertical" 
tools:ignore="MissingPrefix"> 

<android.support.constraint.Guideline 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:id="@+id/guideline" 
    android:orientation="horizontal" 
    app:layout_constraintGuide_percent="0.1"/> 

<android.support.constraint.Guideline 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:id="@+id/guideline2" 
    android:orientation="horizontal" 
    app:layout_constraintGuide_percent="0.9"/> 

<android.support.v7.widget.CardView 
    android:layout_height="wrap_content" 
    android:layout_width="match_parent" 
    app:cardBackgroundColor="?android:attr/windowBackground" 

    app:layout_constraintTop_toTopOf="@+id/guideline"> 

    <android.support.v7.widget.RecyclerView 
     android:id="@+id/recyclerView" 
     android:layout_height="wrap_content" 
     android:layout_width="match_parent" /> 
</android.support.v7.widget.CardView> 

tu jestem zakładając, że chcesz zostawić w przybliżeniu 10% powierzchni ekranu pusty na wierzchu. Jeśli chcesz mniej lub więcej, dostosuj.

Gdy użytkownik zacznie przewijać, możesz dostosować górne ograniczenie widoku Cardview do górnej części elementu nadrzędnego, a po dotarciu do dolnej części listy możesz dostosować dolne ograniczenie widoku Card View do wartości guideline2, co spowoduje 10% spadek miejsca na ekranie poniżej.

To powinno osiągnąć pożądany efekt bez problemów związanych z wydajnością, ponieważ rezygnujesz z widoku przewijania.

Proszę dać mi znać, jeśli chcesz, abym szczegółowo omawiał jakąkolwiek część mojej odpowiedzi.

4

Podejmując decyzję o zmanipulowanym adapterze Oknesif, stworzyłem adapter z trzema układami (topitem, middleitem, bottomitem) z dwoma kształtami do rysowania XML dla topitem i bottomitem. W ten sposób mogłem całkowicie pozbyć się NestedScrollView i CardView.

To jak to wygląda:

enter image description here

A oto kod.Po pierwsze, MainActivity:

public class MainActivity extends AppCompatActivity { 
    final static int LIST_SIZE = 100; 

    final static int TOP = 0; 
    final static int BOTTOM = LIST_SIZE; 
    final static int MIDDLE = 1; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 

     setContentView(R.layout.activity); 

     final ArrayList<Integer> list = new ArrayList<>(); 
     for (int i = 0; i < LIST_SIZE; i++) { 
      list.add(i); 
     } 

     class Viewholder extends RecyclerView.ViewHolder { 
      TextView textView; 

      Viewholder(View itemView) { 
       super(itemView); 
       textView = itemView.findViewById(R.id.textView); 
      } 
     } 

     RecyclerView recyclerView = findViewById(R.id.recyclerView); 
     final RecyclerView.Adapter<Viewholder> adapter = new RecyclerView.Adapter<Viewholder>() { 
      LayoutInflater inflater = LayoutInflater.from(MainActivity.this); 

      @Override 
      public Viewholder onCreateViewHolder(ViewGroup parent, int viewType) { 
       switch (viewType) { 
        case TOP: 
         return new Viewholder(inflater.inflate(R.layout.topitem, parent, false)); 
        case BOTTOM: 
         return new Viewholder(inflater.inflate(R.layout.bottomitem, parent, false)); 
        case MIDDLE: 
        default: 
         return new Viewholder(inflater.inflate(R.layout.middleitem, parent, false)); 
       } 
      } 

      @Override 
      public void onBindViewHolder(Viewholder holder, int position) { 
       holder.textView.setText(String.valueOf(list.get(position))); 
       if (position != 0 && position != LIST_SIZE - 1) { 
        int color = position % 2 == 0 ? android.R.color.holo_orange_dark : android.R.color.holo_orange_light; 
        holder.itemView.setBackgroundColor(getResources().getColor(color)); 
       } 
      } 

      @Override 
      public int getItemCount() { 
       return LIST_SIZE; 
      } 

      @Override 
      public int getItemViewType(int position) { 
       int itemViewType; 
       switch (position) { 
        case 0: 
         itemViewType = TOP; 
         break; 
        case LIST_SIZE - 1: 
         itemViewType = BOTTOM; 
         break; 
        default: 
         itemViewType = MIDDLE; 
       } 
       return itemViewType; 
      } 
     }; 
     recyclerView.setAdapter(adapter); 
     recyclerView.setLayoutManager(new LinearLayoutManager(MainActivity.this)); 
    } 
} 

res/layout/activity.xml:

<?xml version="1.0" encoding="utf-8"?> 
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:id="@+id/containerLayout" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:orientation="vertical"> 

    <android.support.v7.widget.RecyclerView 
     android:id="@+id/recyclerView" 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content" 
     android:clipToPadding="false" 
     android:paddingLeft="25dp" 
     android:paddingRight="25dp" /> 
</android.support.design.widget.CoordinatorLayout> 

res/layout/topitem.xml:

<?xml version="1.0" encoding="utf-8"?> 
<TextView xmlns:android="http://schemas.android.com/apk/res/android" 
    android:id="@+id/textView" 
    android:layout_width="match_parent" 
    android:layout_height="wrap_content" 
    android:background="@drawable/topbackground" 
    android:layout_marginTop="50dp" 
    android:textAlignment="center" 
    android:textColor="@android:color/white" 
    android:textSize="24sp" 
    android:textStyle="bold" /> 

res/layout/middleitem.xml:

<?xml version="1.0" encoding="utf-8"?> 
<TextView xmlns:android="http://schemas.android.com/apk/res/android" 
    android:id="@+id/textView" 
    android:layout_width="match_parent" 
    android:layout_height="wrap_content" 
    android:textAlignment="center" 
    android:textColor="@android:color/white" 
    android:textSize="24sp" 
    android:textStyle="bold" /> 

res/layout/bottomitem.xml:

<?xml version="1.0" encoding="utf-8"?> 
<TextView xmlns:android="http://schemas.android.com/apk/res/android" 
    android:id="@+id/textView" 
    android:layout_width="match_parent" 
    android:layout_height="wrap_content" 
    android:background="@drawable/bottombackground" 
    android:layout_marginBottom="50dp" 
    android:textAlignment="center" 
    android:textColor="@android:color/white" 
    android:textSize="24sp" 
    android:textStyle="bold" /> 

res/drawable/topbackground.xml:

<?xml version="1.0" encoding="utf-8"?> 
<shape xmlns:android="http://schemas.android.com/apk/res/android" 
    android:shape="rectangle"> 
    <corners 
     android:topLeftRadius="5dp" 
     android:topRightRadius="5dp" /> 
    <solid android:color="@android:color/holo_orange_dark" /> 
</shape> 

res/drawable/bottombackground.xml:

<?xml version="1.0" encoding="utf-8"?> 
<shape xmlns:android="http://schemas.android.com/apk/res/android" 
    android:shape="rectangle"> 
    <corners 
     android:bottomLeftRadius="5dp" 
     android:bottomRightRadius="5dp" /> 
    <solid android:color="@android:color/holo_orange_light" /> 
</shape> 

EDIT:

Dodanie tej linii do dna układów elementów XML:

android:elevation="12dp" 

i zmieniając tło na biały, daje następujący wynik:

enter image description here

+0

Czy możesz spróbować na białym tle z elewacją na komórkach? Jestem pewna, że ​​będą zachodzić cienie na boczne oddzielenie każdej komórki. To jest główny powód, dla którego celem jest użycie tylko 1 widoku karty dla całej listy. – pdegand59

+0

Twój cień jest obcięty z boku. Dodaj 'clipToPadding =" false "' do widoku recycler – pdegand59

+0

Tak, miałeś rację. Są "cienie" wychodzące z separacji komórek, gdy padding nie jest obcięty i kiedy jest elewacja na wszystkich trzech układach. Jednak użycie elewacji w dolnym układzie daje tylko wynik, który właśnie wysłałem. Czy to jest to, czego chcesz? – kalabalik

1

To tylko prosta linia kodu

recycler.setNestedScrollingEnabled(false); 

i nie zapomnij, aby wysokość cardview do wrap_content

Powiązane problemy