I have a HorizontalScrollView with a ConstraintLayout containing two recycler views (reason is, i want to scroll both datasets together).
The problem I have is the HorizontalScrollView is clipping (see circled red area). I need to be able to see the inner views extended out beyond the HorizontalScrollView.
It is worth noting that I do not want to make the view match_parent and simply add a margin to the start/end - the reason for this is because the app is using a keypad for navigation and i would like the highlight to be within the pink area.
When i match_parent with padding, navigating causes an issue where for example, navigating back to the start (left hand) of the menu when its off-screen, the first delegate when highlighted will be right up against the edge of the screen and it requires an additional left press to get the padding (white area to the left of the pink) to show. Essentially - the handset highlight should always be within the pink area! Hopefully that makes sense!
So for me I believe the solution is like below, but to get clipping disabled in the HorizontalScrollView - which I have currently not been able to get working.
To make things slightly more tricky - the solution needs to work with API 19-21.
MainActivity.java
public class MainActivity extends AppCompatActivity {
RVAdapter topAdapter;
RVAdapter bottomAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ArrayList<String> topItems = new ArrayList<>();
topItems.add("Top 1");
topItems.add("Top 2");
topItems.add("Top 3");
topItems.add("Top 4");
topItems.add("Top 5");
topItems.add("Top 6");
topItems.add("Top 7");
topItems.add("Top 8");
topItems.add("Top 9");
topItems.add("Top 10");
RecyclerView topRV = findViewById(R.id.topMenu);
topRV.setLayoutManager(new LinearLayoutManager(this, RecyclerView.HORIZONTAL, false));
ItemDecoration topDecoration = new ItemDecoration(40);
topRV.addItemDecoration(topDecoration);
topAdapter = new RVAdapter(this, topItems);
topRV.setAdapter(topAdapter);
ArrayList<String> bottomItems = new ArrayList<>();
bottomItems.add("Bottom 1");
bottomItems.add("Bottom 2");
bottomItems.add("Bottom 3");
bottomItems.add("Bottom 4");
bottomItems.add("Bottom 5");
bottomItems.add("Bottom 6");
bottomItems.add("Bottom 7");
bottomItems.add("Bottom 8");
bottomItems.add("Bottom 9");
bottomItems.add("Bottom 10");
RecyclerView bottomRV = findViewById(R.id.bottomMenu);
ItemDecoration bottomDecoration = new ItemDecoration(40);
bottomRV.addItemDecoration(bottomDecoration);
bottomRV.setLayoutManager(new LinearLayoutManager(this, RecyclerView.HORIZONTAL, false));
bottomAdapter = new RVAdapter(this, bottomItems);
bottomRV.setAdapter(bottomAdapter);
}
static class ItemDecoration extends RecyclerView.ItemDecoration {
private final int itemSpacing;
public ItemDecoration(int itemSpacing) {
this.itemSpacing = itemSpacing;
}
@Override
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
outRect.left = itemSpacing;
}
} //ItemDecoration
}
RVAdapter.java
class RVAdapter extends RecyclerView.Adapter<RVAdapter.ViewHolder>{
private LayoutInflater mInflater;
private List<String> mData;
// data is passed into the constructor
RVAdapter(Context context, List<String> data) {
this.mInflater = LayoutInflater.from(context);
this.mData = data;
}
@NonNull
@Override
public RVAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = mInflater.inflate(R.layout.list_item, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull RVAdapter.ViewHolder holder, int position) {
String text = mData.get(position);
holder.myTextView.setText(text);
}
@Override
public int getItemCount() {
return 10;
}
// stores and recycles views as they are scrolled off screen
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
AppCompatTextView myTextView;
ViewHolder(View itemView) {
super(itemView);
myTextView = itemView.findViewById(R.id.info);
itemView.setOnClickListener(this);
}
@Override
public void onClick(View view) {
Log.d("RVAdapter", mData.get(getAdapterPosition()) + " clicked!");
}
}
}
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"
tools:context=".MainActivity">
<androidx.constraintlayout.widget.Guideline
android:id="@+id/leftGuide"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_begin="50px"/>
<androidx.constraintlayout.widget.Guideline
android:id="@+id/RightGuide"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_end="50px"/>
<HorizontalScrollView
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="@id/leftGuide"
app:layout_constraintEnd_toEndOf="@id/RightGuide"
android:clipChildren="false"
android:background="#80ff00ff">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/wrapper"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:nestedScrollingEnabled="false">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/topMenu"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:nestedScrollingEnabled="false"
android:orientation="horizontal"
android:overScrollMode="never"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="@layout/list_item"
tools:itemCount="10"
tools:orientation="horizontal"
tools:scrollbars="horizontal"/>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/bottomMenu"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/topMenu"
android:layout_marginTop="50px"
android:nestedScrollingEnabled="false"
android:orientation="horizontal"
android:overScrollMode="never"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="@layout/list_item"
tools:itemCount="10"
tools:orientation="horizontal"
tools:scrollbars="horizontal"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</HorizontalScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>
list_item.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/info"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="17sp"
tools:text="Test Test Test"/>
</androidx.constraintlayout.widget.ConstraintLayout>