I am developing a Game fans app. I want to create a layout given below
I have great experience in making custom recycelerviews with multiple LAYOUT_VIEW_TYPES.
My question is this the best way to create that recyclerview or I can do this in more easyway
CodePudding user response:
Yes the best way to achieve that result is by creating a recyclerview with multiple layouts and I think that it's the only way if you are using xml.
But this could be a lot easier if you make it using jetpack compose
no need for recycler view or adapter anymore with compose and you can make any custom layout that you want.
CodePudding user response:
Phew... Finally I did it with Recyclerview custom layout items left and right.
Sharing my work.
here is my layout_item_time_line_left.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="wrap_content"
tools:context=".livescore.TimeLineFragment">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@ id/constraintLayout2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="5dp"
android:background="@drawable/rounded_corner_time_line_item_bg"
android:padding="10dp"
app:layout_constraintEnd_toStartOf="@ id/txtPlayerName2"
app:layout_constraintTop_toTopOf="parent">
<com.mikhaellopez.circularimageview.CircularImageView
android:id="@ id/imgPlayerImage"
android:layout_width="32dp"
android:layout_height="32dp"
android:src="@drawable/img_upload_profile"
app:border_color="@color/white"
app:civ_border_width="1dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:selector_stroke_color="@color/white" />
<TextView
android:id="@ id/txtPlayerName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_marginStart="5dp"
android:gravity="center_horizontal"
android:text="Neymar"
android:textColor="#66666a"
android:textSize="12sp"
app:layout_constraintStart_toEndOf="@ id/imgPlayerImage"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@ id/txtEventName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_marginStart="5dp"
android:gravity="center_horizontal"
android:text="Goal"
android:textColor="@color/txt_color_live_score"
android:textSize="12sp"
app:layout_constraintStart_toEndOf="@ id/imgPlayerImage"
app:layout_constraintTop_toBottomOf="@ id/txtPlayerName" />
<com.mikhaellopez.circularimageview.CircularImageView
android:id="@ id/imgEventImage"
android:layout_width="12dp"
android:layout_height="12dp"
android:layout_marginStart="4dp"
android:layout_marginTop="2dp"
android:src="@drawable/ic_sports_footbal"
app:border_width="1dp"
app:civ_border_width="1dp"
app:layout_constraintStart_toEndOf="@ id/txtEventName"
app:layout_constraintTop_toBottomOf="@ id/txtPlayerName"
app:selector_stroke_color="@color/white" />
</androidx.constraintlayout.widget.ConstraintLayout>
<ImageView
android:id="@ id/imgEventImage2"
android:layout_width="12dp"
android:layout_height="12dp"
android:scaleType="fitXY"
android:src="@drawable/ic_online"
app:border_width="1dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:selector_stroke_color="@color/white" />
<View
android:id="@ id/viewLineUpper"
android:layout_width="1dp"
android:layout_height="20dp"
android:background="#41415A"
app:layout_constraintBottom_toTopOf="@ id/imgEventImage2"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<View
android:id="@ id/viewLineLower"
android:layout_width="1dp"
android:layout_height="20dp"
android:background="#41415A"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@ id/imgEventImage2" />
<TextView
android:id="@ id/txtPlayerName2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_marginTop="15dp"
android:gravity="center_horizontal"
android:text="33''"
android:textColor="#66666a"
android:textSize="8sp"
app:layout_constraintEnd_toStartOf="@ id/imgEventImage2"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
here is my layout_item_time_line_right.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="wrap_content">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@ id/constraintLayout2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:background="@drawable/rounded_corner_time_line_item_bg"
android:padding="10dp"
app:layout_constraintStart_toEndOf="@ id/txtPlayerName2"
app:layout_constraintTop_toTopOf="parent">
<com.mikhaellopez.circularimageview.CircularImageView
android:id="@ id/imgPlayerImage"
android:layout_width="32dp"
android:layout_height="32dp"
android:src="@drawable/img_upload_profile"
app:border_color="@color/white"
app:civ_border_width="1dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:selector_stroke_color="@color/white" />
<TextView
android:id="@ id/txtPlayerName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_marginStart="5dp"
android:gravity="center_horizontal"
android:text="Neymar"
android:textColor="#66666a"
android:textSize="12sp"
app:layout_constraintStart_toEndOf="@ id/imgPlayerImage"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@ id/txtEventName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_marginStart="5dp"
android:gravity="center_horizontal"
android:text="Goal"
android:textColor="@color/txt_color_live_score"
android:textSize="12sp"
app:layout_constraintStart_toEndOf="@ id/imgPlayerImage"
app:layout_constraintTop_toBottomOf="@ id/txtPlayerName" />
<com.mikhaellopez.circularimageview.CircularImageView
android:id="@ id/imgEventImage"
android:layout_width="12dp"
android:layout_height="12dp"
android:layout_marginStart="4dp"
android:layout_marginTop="2dp"
android:src="@drawable/ic_sports_footbal"
app:civ_border_width="1dp"
app:layout_constraintStart_toEndOf="@ id/txtEventName"
app:layout_constraintTop_toBottomOf="@ id/txtPlayerName"
app:selector_stroke_color="@color/white" />
</androidx.constraintlayout.widget.ConstraintLayout>
<ImageView
android:id="@ id/imgEventImage2"
android:layout_width="12dp"
android:layout_height="12dp"
android:scaleType="fitXY"
android:src="@drawable/ic_online"
app:border_width="1dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:selector_stroke_color="@color/white" />
<View
android:id="@ id/viewLineUpper"
android:layout_width="1dp"
android:layout_height="20dp"
android:background="#41415A"
app:layout_constraintBottom_toTopOf="@ id/imgEventImage2"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<View
android:id="@ id/viewLineLower"
android:layout_width="1dp"
android:layout_height="20dp"
android:background="#41415A"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@ id/imgEventImage2" />
<TextView
android:id="@ id/txtPlayerName2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_marginTop="15dp"
android:gravity="center_horizontal"
android:text="33''"
android:textColor="#66666a"
android:textSize="8sp"
app:layout_constraintStart_toEndOf="@ id/imgEventImage2"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
here is my fragment fragment_time_line.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView 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:background="#020321"
tools:context=".livescore.TimeLineFragment">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@ id/constraintLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:background="@drawable/rounded_border_live_score_tab_table"
android:padding="10dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:id="@ id/txtBallPossession"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:gravity="center_horizontal"
android:text="Ball possession"
android:textColor="#66666a"
android:textSize="12sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<LinearLayout
android:id="@ id/layout_possession_percentage"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:orientation="horizontal"
app:layout_constraintTop_toBottomOf="@ id/txtBallPossession"
tools:layout_editor_absoluteX="0dp">
<TextView
android:id="@ id/txtLeftPercentage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:text="70%"
android:textColor="#00ffac"
android:textSize="12sp"
android:textStyle="bold" />
<ProgressBar
android:id="@ id/progressBarLeft"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_weight="1"
android:indeterminate="false"
android:indeterminateTint="#00ffac"
android:max="100"
android:progress="50"
android:rotation="180" />
<TextView
android:id="@ id/txtRightPercentage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="30%"
android:textColor="#ff0909"
android:textSize="12sp"
android:textStyle="bold" />
</LinearLayout>
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:background="@drawable/rounded_corner_card"
android:clipToOutline="true"
android:scaleType="fitXY"
android:src="@drawable/img_footbal_ground_green"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@ id/layout_possession_percentage" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@ id/recycler_view_match_timeline"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@ id/constraintLayout" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>
and here is my JAVA code for fragment
/**
* A simple {@link Fragment} subclass.
* Use the {@link TimeLineFragment#newInstance} factory method to
* create an instance of this fragment.
*/
public class TimeLineFragment extends Fragment {
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;
public TimeLineFragment() {
// Required empty public constructor
}
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* @param param1 Parameter 1.
* @param param2 Parameter 2.
* @return A new instance of fragment TimeLineFragment.
*/
// TODO: Rename and change types and number of parameters
public static TimeLineFragment newInstance(String param1, String param2) {
TimeLineFragment fragment = new TimeLineFragment();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}
}
private View mView;
private RecyclerView recyclerViewMatchTimeline;
private ArrayList<MatchTimeLine> items = new ArrayList<>();
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
mView = inflater.inflate(R.layout.fragment_time_line, container, false);
recyclerViewMatchTimeline = mView.findViewById(R.id.recycler_view_match_timeline);
LinearLayoutManager matchTimelineLayoutManager = new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false);
recyclerViewMatchTimeline.setHasFixedSize(true);
recyclerViewMatchTimeline.setLayoutManager(matchTimelineLayoutManager);
recyclerViewMatchTimeline.setAdapter(new TimeLineMatchEventsRecyclerViewAdapter(items));
return mView;
}
}
and lastly my magic Adapter TimeLineMatchEventsRecyclerViewAdapter.java
(copied from stackoverflow answer)
public class TimeLineMatchEventsRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private List<MatchTimeLine> mModelList;
public TimeLineMatchEventsRecyclerViewAdapter(List<MatchTimeLine> modelList) {
this.mModelList = modelList;
}
@Override
public int getItemViewType(int position) {
// Just as an example, return 0 or 2 depending on position
// Note that unlike in ListView adapters, types don't have to be contiguous
return position % 2 * 2;
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
switch (viewType) {
case 0:
LayoutItemTimeLineLeftBinding bindingLeftView = LayoutItemTimeLineLeftBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false);
return new ViewHolderLeft(bindingLeftView);
case 2:
LayoutItemTimeLineRightBinding bindingRightView = LayoutItemTimeLineRightBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false);
return new ViewHolderRight(bindingRightView);
default:
LayoutItemTimeLineRightBinding bindingRightDefault = LayoutItemTimeLineRightBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false);
return new ViewHolderRight(bindingRightDefault);
}
}
@Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, @SuppressLint("RecyclerView") int position) {
// final Team team = mModelList.get(position);
switch (holder.getItemViewType()) {
case 0:
ViewHolderLeft viewHolderLeft = (ViewHolderLeft) holder;
break;
case 2:
ViewHolderRight viewHolderRight = (ViewHolderRight) holder;
break;
}
}
@Override
public int getItemCount() {
// return mModelList == null ? 0 : mModelList.size();
return 20;
}
class ViewHolderLeft extends RecyclerView.ViewHolder {
LayoutItemTimeLineLeftBinding binding;
public ViewHolderLeft(LayoutItemTimeLineLeftBinding binding) {
super(binding.getRoot());
this.binding = binding;
}
}
class ViewHolderRight extends RecyclerView.ViewHolder {
LayoutItemTimeLineRightBinding binding;
public ViewHolderRight(LayoutItemTimeLineRightBinding binding) {
super(binding.getRoot());
this.binding = binding;
}
}
}
Here is the output I got