【发布时间】:2022-09-23 19:29:14
【问题描述】:
我有两个单独的水平 RecyclerView 嵌入在垂直 LinearLayout 中,它本身包含在 NestedScrollView 中 - 顶部和底部视图具有不同的数据集,最终将具有不同的布局。
我目前无法让 NestedScrollView 滚动内容。相反,两个 RecyclerView 都在独立处理自己的滚动行为。所需的行为是滚动 NestedScrollView 会滚动两个 RecyclerView(LinearLayout 的内容),因此它看起来像一个菜单。
我看过许多类似的 SO 线程,但我似乎无法让它工作。我尝试过诸如..
- 设置填充视口
- LinearLayout 最初是一个 ConstraintLayout,但是很多帖子建议切换到 LinearLayout,所以坚持使用
- setNestedScrollingEnabled(在两个 RecyclerViews 的代码和 xml 中都尝试过)
- 试过 ScrollView 和 NestedScrollView。嵌套似乎是正确的。
这是代码..
MainActivity.java
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
public class MainActivity extends AppCompatActivity {
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (hasFocus) {
getWindow().getDecorView().setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// remove title
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
setContentView(R.layout.activity_main);
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.replace(R.id.content, new SyncedListsActivity())
.commitNow();
}
}
}
SyncedListsActivity.java
import android.graphics.Rect;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import androidx.core.widget.NestedScrollView;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
public class SyncedListsActivity extends Fragment {
View v;
NestedScrollView scrollView;
LinearLayout scrollContent;
RecyclerView topMenu;
TopAdapter topAdapter;
RecyclerView bottomMenu;
BottomAdapter bottomAdapter;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Log.d(\"SyncedListsActivity\", \"onCreateView\");
super.onCreate(savedInstanceState);
if(v==null) {
Log.d(\"SyncedListsActivity\", \"v is NULL recreating\");
v = inflater.inflate(R.layout.activity_synced_scroll, container, false);
scrollView = v.findViewById(R.id.scrollContainer);
scrollContent = v.findViewById(R.id.wrapper);
topMenu = v.findViewById(R.id.topList);
topMenu.setNestedScrollingEnabled(false);
bottomMenu = v.findViewById(R.id.bottomList);
bottomMenu.setNestedScrollingEnabled(false);
setupTopMenu();
setupBottomMenu();
}
return v;
}
private void setupTopMenu() {
topMenu.setLayoutManager(new LinearLayoutManager(requireContext(), LinearLayoutManager.HORIZONTAL, false));
topAdapter = new TopAdapter(getActivity(),this);
topMenu.setAdapter(topAdapter);
topAdapter.notifyDataSetChanged();
SpacesItemDecoration decoration = new SpacesItemDecoration(12);
topMenu.addItemDecoration(decoration);
}
private void setupBottomMenu() {
bottomMenu.setLayoutManager(new LinearLayoutManager(requireContext(), LinearLayoutManager.HORIZONTAL, false));
bottomAdapter = new BottomAdapter(getActivity(),this);
bottomMenu.setAdapter(bottomAdapter);
bottomAdapter.notifyDataSetChanged();
SpacesItemDecoration decoration = new SpacesItemDecoration(12);
bottomMenu.addItemDecoration(decoration);
}
@Override
public void onResume() {
super.onResume();
Log.d(\"SyncedListsActivity\", \"onResume\");
if(topMenu == null) {
setupTopMenu();
}
if(bottomMenu == null) {
setupBottomMenu();
}
}
}
class SpacesItemDecoration extends RecyclerView.ItemDecoration {
private int space;
public SpacesItemDecoration(int space) {
this.space = space;
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
outRect.left = space;
outRect.right = space;
outRect.top = space;
if (parent.getChildLayoutPosition(view) == 0) {
outRect.left = 0;
}
}
}
委托瓦片.java
class DelegateTile {
private int pk; //primary key used by recyclerview DiffUtil to simplify adding/removing items. Can probably use a CID value for this!
private String title;
private String color;
private int width;
private int viewType;
public DelegateTile(int pk, String title, String color, int width, int viewType) {
this.pk = pk;
this.title = title;
this.color = color;
this.width = width;
this.viewType = viewType;
}
public int getPk() { return pk; }
public int getTileType() {
return viewType;
}
public String getTitle() {
return title;
}
public String getColor() {
return color;
}
public int getSize() {
return width;
}
}
TopAdapter.java
import android.content.Context;
import android.graphics.Color;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
import java.util.List;
public class TopAdapter extends RecyclerView.Adapter<TopAdapter.TopAdapterView> {
private Context context;
private Fragment parent;
private List<DelegateTile> tileDefinitions;
public TopAdapter(Context context, SyncedListsActivity parent) {
this.context = context;
this.parent = parent;
//Create tiles
tileDefinitions = new ArrayList<>();
tileDefinitions.add(new DelegateTile(0, \"Item 1\", \"9E0026\", 800, 0));
tileDefinitions.add(new DelegateTile(1, \"Item 2\", \"539E3E\", 400, 1));
tileDefinitions.add(new DelegateTile(2, \"Item 3\", \"F89B1C\", 800, 0));
tileDefinitions.add(new DelegateTile(3, \"Item 4\", \"13ADA0\", 400, 1));
tileDefinitions.add(new DelegateTile(4, \"Item 5\", \"00507E\", 400, 1));
tileDefinitions.add(new DelegateTile(5, \"Item 6\", \"555555\", 800, 0));
}
@Override
public TopAdapterView onCreateViewHolder(ViewGroup parent, int viewType) {
TopAdapterView gridAdapterView = null;
Log.d(\"TOP_RECYCLER\", \"onCreateViewHolder \" + viewType + \" rendering\");
switch (viewType) {
case 0: { //Wide tile
Log.d(\"TOP_RECYCLER\", \"onCreateViewHolder \" + viewType + \" TILE_TYPE_WIDE\");
View layoutView = LayoutInflater.from(parent.getContext()).inflate(R.layout.tile_wide, parent, false);
gridAdapterView = new TopAdapterView(layoutView, viewType);
break;
}
case 1: { //normal width tile
Log.d(\"TOP_RECYCLER\", \"onCreateViewHolder \" + viewType + \" TILE_TYPE_STANDARD\");
View layoutView = LayoutInflater.from(parent.getContext()).inflate(R.layout.tile_normal, parent, false);
gridAdapterView = new TopAdapterView(layoutView, viewType);
break;
}
}
return gridAdapterView;
}
@Override
public void onBindViewHolder(TopAdapterView holder, int position) {
/*
different styles for different cells - Slideshow, tiles, Footer
*/
switch (tileDefinitions.get(position).getTileType()) {
case 0: { //wide tile
//Tiles - set tile behavior
holder.title.setText(tileDefinitions.get(position).getTitle());
//Dynamic colors for our tiles
ViewGroup.LayoutParams params = holder.layout.getLayoutParams();
params.width = tileDefinitions.get(position).getSize(); //setting width
holder.layout.setLayoutParams(params);
holder.layout.setBackgroundColor(Color.parseColor(\"#\" + tileDefinitions.get(position).getColor())); //setting color
holder.layout.setTag(position);
//margins
ViewGroup.MarginLayoutParams llparams = (ViewGroup.MarginLayoutParams) holder.layout.getLayoutParams();
llparams.rightMargin = 5;
}
case 1: { //normal width tile
//Tiles - set tile behavior
holder.title.setText(tileDefinitions.get(position).getTitle());
//Dynamic colors for our tiles
ViewGroup.LayoutParams params = holder.layout.getLayoutParams();
params.width = tileDefinitions.get(position).getSize(); //setting width
holder.layout.setLayoutParams(params);
holder.layout.setBackgroundColor(Color.parseColor(\"#\" + tileDefinitions.get(position).getColor())); //setting color
holder.layout.setTag(position);
//margins
ViewGroup.MarginLayoutParams llparams = (ViewGroup.MarginLayoutParams) holder.layout.getLayoutParams();
llparams.rightMargin = 5;
break;
}
}
}
@Override
public int getItemCount() {
return tileDefinitions == null ? 0 : tileDefinitions.size();
}
@Override
public int getItemViewType(int position) {
// Return type based on position
return tileDefinitions.get(position).getTileType();
}
class TopAdapterView extends RecyclerView.ViewHolder {
TextView title;
LinearLayout layout;
public TopAdapterView(View itemView, int type) {
super(itemView);
switch (type) {
case 0: { //wide tile
title = itemView.findViewById(R.id.txtTitle);
layout = itemView.findViewById(R.id.wide_layout);
break;
}
case 1: { //normal width tile
title = itemView.findViewById(R.id.txtTitle);
layout = itemView.findViewById(R.id.normal_layout);
break;
}
}
}
}
}
底部适配器.java
import android.content.Context;
import android.graphics.Color;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
import java.util.List;
public class BottomAdapter extends RecyclerView.Adapter<BottomAdapter.BottomAdapterView> {
private Context context;
private Fragment parent;
private List<DelegateTile> tileDefinitions;
public BottomAdapter(Context context, SyncedListsActivity parent) {
this.context = context;
this.parent = parent;
//Create tiles
tileDefinitions = new ArrayList<>();
tileDefinitions.add(new DelegateTile(0, \"Item 1\", \"A21E23\", 400, 1)); //1
tileDefinitions.add(new DelegateTile(1, \"Item 2\", \"008EAA\", 800, 0)); //2
tileDefinitions.add(new DelegateTile(2, \"Item 3\", \"A8CF5A\", 400, 1)); //5
tileDefinitions.add(new DelegateTile(3, \"Item 4\", \"814199\", 400, 1)); //6
tileDefinitions.add(new DelegateTile(4, \"Item 5\", \"0093B2\", 800, 0)); //7
tileDefinitions.add(new DelegateTile(5, \"Item 6\", \"13ADA0\", 400, 1)); //6
tileDefinitions.add(new DelegateTile(6, \"Item 7\", \"00507E\", 400, 1)); //7
}
@Override
public BottomAdapterView onCreateViewHolder(ViewGroup parent, int viewType) {
BottomAdapterView gridAdapterView = null;
Log.d(\"BOTTOM_RECYCLER\", \"onCreateViewHolder \" + viewType + \" rendering\");
switch (viewType) {
case 0: { //Wide tile
Log.d(\"BOTTOM_RECYCLER\", \"onCreateViewHolder \" + viewType + \" TILE_TYPE_WIDE\");
View layoutView = LayoutInflater.from(parent.getContext()).inflate(R.layout.tile_wide, parent, false);
gridAdapterView = new BottomAdapterView(layoutView, viewType);
break;
}
case 1: { //normal width tile
Log.d(\"BOTTOM_RECYCLER\", \"onCreateViewHolder \" + viewType + \" TILE_TYPE_STANDARD\");
View layoutView = LayoutInflater.from(parent.getContext()).inflate(R.layout.tile_normal, parent, false);
gridAdapterView = new BottomAdapterView(layoutView, viewType);
break;
}
}
return gridAdapterView;
}
@Override
public void onBindViewHolder(BottomAdapterView holder, int position) {
/*
different styles for different cells - Slideshow, tiles, Footer
*/
switch (tileDefinitions.get(position).getTileType()) {
case 0: { //wide tile
//Tiles - set tile behavior
holder.title.setText(tileDefinitions.get(position).getTitle());
//Dynamic colors for our tiles
ViewGroup.LayoutParams params = holder.layout.getLayoutParams();
params.width = tileDefinitions.get(position).getSize(); //setting width
holder.layout.setLayoutParams(params);
holder.layout.setBackgroundColor(Color.parseColor(\"#\" + tileDefinitions.get(position).getColor())); //setting color
holder.layout.setTag(position);
//margins
ViewGroup.MarginLayoutParams llparams = (ViewGroup.MarginLayoutParams) holder.layout.getLayoutParams();
llparams.rightMargin = 5;
}
case 1: { //normal width tile
//Tiles - set tile behavior
holder.title.setText(tileDefinitions.get(position).getTitle());
//Dynamic colors for our tiles
ViewGroup.LayoutParams params = holder.layout.getLayoutParams();
params.width = tileDefinitions.get(position).getSize(); //setting width
holder.layout.setLayoutParams(params);
holder.layout.setBackgroundColor(Color.parseColor(\"#\" + tileDefinitions.get(position).getColor())); //setting color
holder.layout.setTag(position);
//margins
ViewGroup.MarginLayoutParams llparams = (ViewGroup.MarginLayoutParams) holder.layout.getLayoutParams();
llparams.rightMargin = 5;
break;
}
}
}
@Override
public int getItemCount() {
return tileDefinitions == null ? 0 : tileDefinitions.size();
}
@Override
public int getItemViewType(int position) {
// Return type based on position
return tileDefinitions.get(position).getTileType();
}
class BottomAdapterView extends RecyclerView.ViewHolder {
TextView title;
LinearLayout layout;
public BottomAdapterView(View itemView, int type) {
super(itemView);
switch (type) {
case 0: { //wide tile
title = itemView.findViewById(R.id.txtTitle);
layout = itemView.findViewById(R.id.wide_layout);
break;
}
case 1: { //normal width tile
title = itemView.findViewById(R.id.txtTitle);
layout = itemView.findViewById(R.id.normal_layout);
break;
}
}
}
}
}
activity_main.xml
<?xml version=\"1.0\" encoding=\"utf-8\"?>
<androidx.constraintlayout.widget.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:layout_width=\"match_parent\"
android:layout_height=\"match_parent\"
android:id=\"@+id/main_root\"
android:layout_margin=\"20dp\"
android:clipToPadding=\"false\"
android:clipChildren=\"false\">
<FrameLayout
android:id=\"@+id/content\"
android:layout_width=\"0dp\"
android:layout_height=\"0dp\"
app:layout_constraintBottom_toBottomOf=\"parent\"
app:layout_constraintEnd_toEndOf=\"parent\"
app:layout_constraintStart_toStartOf=\"parent\"
app:layout_constraintTop_toTopOf=\"parent\"
android:clipChildren=\"false\"
android:clipToPadding=\"false\" />
</androidx.constraintlayout.widget.ConstraintLayout>
activity_synced_scroll.xml
<?xml version=\"1.0\" encoding=\"utf-8\"?>
<androidx.constraintlayout.widget.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:layout_width=\"match_parent\"
android:layout_height=\"match_parent\"
android:id=\"@+id/main_root\"
android:clipToPadding=\"false\"
android:clipChildren=\"false\">
<androidx.core.widget.NestedScrollView
android:id=\"@+id/scrollContainer\"
android:layout_width=\"match_parent\"
android:layout_height=\"wrap_content\"
android:orientation=\"horizontal\"
app:layout_constraintTop_toTopOf=\"parent\"
app:layout_constraintBottom_toBottomOf=\"parent\">
<LinearLayout
android:id=\"@+id/wrapper\"
android:orientation=\"vertical\"
android:layout_width=\"match_parent\"
android:layout_height=\"wrap_content\">
<androidx.recyclerview.widget.RecyclerView
android:id=\"@+id/topList\"
android:layout_width=\"wrap_content\"
android:layout_height=\"wrap_content\"
android:orientation=\"horizontal\"
app:layout_constraintTop_toTopOf=\"parent\"
app:layout_constraintBottom_toTopOf=\"@id/bottomList\"
app:layout_constraintStart_toStartOf=\"parent\"/>
<androidx.recyclerview.widget.RecyclerView
android:id=\"@+id/bottomList\"
android:layout_width=\"wrap_content\"
android:layout_height=\"wrap_content\"
android:orientation=\"horizontal\"
app:layout_constraintTop_toBottomOf=\"@id/topList\"
app:layout_constraintBottom_toBottomOf=\"parent\"
app:layout_constraintStart_toStartOf=\"parent\"/>
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>
tile_normal.xml
<?xml version=\"1.0\" encoding=\"utf-8\"?>
<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"
android:id=\"@+id/normal_layout\"
android:layout_width=\"400px\"
android:layout_height=\"400px\"
android:orientation=\"vertical\"
android:gravity=\"center\" >
<TextView
android:id=\"@+id/txtTitle\"
android:layout_width=\"wrap_content\"
android:layout_height=\"wrap_content\"
android:gravity=\"center\"
android:textSize=\"25sp\" />
</LinearLayout>
tile_wide.xml
<?xml version=\"1.0\" encoding=\"utf-8\"?>
<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"
android:id=\"@+id/wide_layout\"
android:layout_width=\"800px\"
android:layout_height=\"400px\"
android:orientation=\"vertical\"
android:gravity=\"center\" >
<TextView
android:id=\"@+id/txtTitle\"
android:layout_width=\"wrap_content\"
android:layout_height=\"wrap_content\"
android:gravity=\"center\"
android:textSize=\"25sp\" />
</LinearLayout>
标签: java android android-recyclerview android-nestedscrollview