OneUIProject / oneui-core

Samsung's One UI core libraries for Android apps.
MIT License
119 stars 15 forks source link

Examples #3

Closed veso266 closed 2 years ago

veso266 commented 2 years ago

Hello there, I recently found your awesome library: https://github.com/OneUIProject/OneUI-Design-Library

and was stunned by it, now I was looking for a List view example, something similar that Samsung is showing in their design docs on page 20 slika

But I couldn't find any example, then I found out that that library is deprecated in favour of this one, but here I couldn't find any examples eather

so I was wondering is there any list example like the picture above

Thanks, and thank you for developing this amazing library (wondering why Samsung never released their OneUI library so other people could create apps like samsung)

salvogiangri commented 2 years ago

The new sesl lib is currently W.I.P. and there are still no released artifacts, so there is no documentation as well. To create list views Samsung uses RecyclerView. the usage in both new and old lib is the same as Google one:

You can find an example of its usage in the Sample app of the old lib (the Icons tab), here's also the code relative to it: https://github.com/OneUIProject/OneUI-Design-Library/blob/master/app/src/main/java/de/dlyt/yanndroid/oneuiexample/tabs/IconsTab.java

veso266 commented 2 years ago

Thank you so much, that did it (never knew how this control was called)

I still have some problems with corners not being rounded, and for some reason when I tap the item, no animation is seen, but it works well othervise

MainActivity.java

package si.wolf.internetradio;

import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;

import android.os.Bundle;
import android.util.TypedValue;
import android.view.View;
import android.widget.Toast;

import java.util.ArrayList;

import si.wolf.internetradio.adapters.StationsAdapter;
import si.wolf.internetradio.decorators.SimpleDividerItemDecoration;

import de.dlyt.yanndroid.oneui.view.RecyclerView;                         //Samsung
//import de.dlyt.yanndroid.oneui.view.RecyclerView.ItemDecoration;          //Samsung
import de.dlyt.yanndroid.oneui.sesl.recyclerview.SeslLinearLayoutManager; //Samsung

//import androidx.recyclerview.widget.RecyclerView;                       //Google
//import androidx.recyclerview.widget.LinearLayoutManager;                //Google

public class MainActivity extends AppCompatActivity implements StationsAdapter.ItemClickListener{

    StationsAdapter adapter;

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

        // data to populate the RecyclerView with
        ArrayList<String> animalNames = new ArrayList<>();
        animalNames.add("Horse");
        animalNames.add("Cow");
        animalNames.add("Camel");
        animalNames.add("Sheep");
        animalNames.add("Goat");

        // set up the RecyclerView
        RecyclerView recyclerView = findViewById(R.id.rvStations);
        //recyclerView.setLayoutManager(new LinearLayoutManager(this)); //Google
        recyclerView.setLayoutManager(new SeslLinearLayoutManager(this)); //Samsung
        adapter = new StationsAdapter(this, animalNames);
        adapter.setClickListener((StationsAdapter.ItemClickListener) this);
        recyclerView.setAdapter(adapter);
        recyclerView.setItemAnimator(null);
        //recyclerView.seslSetIndexTipEnabled(true);

        recyclerView.seslSetGoToTopEnabled(true);
        recyclerView.seslSetLastRoundedCorner(true);
        recyclerView.seslSetCtrlkeyPressed(true);

        //If samsung
        recyclerView.seslSetSmoothScrollEnabled(true);

        //divider
//        TypedValue divider = new TypedValue();
//        this.getTheme().resolveAttribute(android.R.attr.listDivider, divider, true);
        //ItemDecoration decoration = new DividerItemDecoration(recyclerView.getContext(), DividerItemDecoration.VERTICAL);
        recyclerView.addItemDecoration(new SimpleDividerItemDecoration(this));
        //decoration.setDivider(this.getDrawable(divider.resourceId));

        //recyclerView.seslSetFillBottomEnabled(true);
        //recyclerView.seslSetFillBottomColor(R.color.recyclerView_divider_color);
    }

    @Override
    public void onItemClick(View view, int position) {
        Toast.makeText(this, "You clicked " + adapter.getItem(position) + " on row number " + position, Toast.LENGTH_SHORT).show();
    }
}

SimpleDecorator.java

package si.wolf.internetradio.decorators;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.view.View;

import androidx.annotation.NonNull;
import androidx.appcompat.util.SeslRoundedCorner;
import androidx.core.content.ContextCompat;

import de.dlyt.yanndroid.oneui.view.RecyclerView;

import si.wolf.internetradio.R;
//import si.wolf.internetradio.adapters.ImageAdapter;

public class SimpleDividerItemDecoration extends RecyclerView.ItemDecoration {
    private Drawable mDivider;

    public SimpleDividerItemDecoration(Context context) {
        mDivider = ContextCompat.getDrawable(context, R.drawable.line_divider);
    }

    @Override
    public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
        int left = parent.getPaddingLeft();
        int right = parent.getWidth() - parent.getPaddingRight();

        int childCount = parent.getChildCount();
        for (int i = 0; i < childCount; i++) {
            View child = parent.getChildAt(i);

            RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();

            int top = child.getBottom() + params.bottomMargin;
            int bottom = top + mDivider.getIntrinsicHeight();

            mDivider.setBounds(left, top, right, bottom);
            mDivider.draw(c);
        }
    }

    /*
    public void setDivider(Drawable d) {
        mDivider = d;
        mDividerHeight = d.getIntrinsicHeight();
        listView.invalidateItemDecorations();
    }
     */
}

StationAdapter.java

package si.wolf.internetradio.adapters;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

//import androidx.recyclerview.widget.RecyclerView;     //Google
import de.dlyt.yanndroid.oneui.view.RecyclerView;       //Samsung

import java.util.List;

import si.wolf.internetradio.R;

public class StationsAdapter extends RecyclerView.Adapter<StationsAdapter.ViewHolder> {

    private List<String> mData;
    private LayoutInflater mInflater;
    private ItemClickListener mClickListener;

    // data is passed into the constructor
    public StationsAdapter(Context context, List<String> data) {
        this.mInflater = LayoutInflater.from(context);
        this.mData = data;
    }

    // inflates the row layout from xml when needed
    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = mInflater.inflate(R.layout.radioview_row, parent, false);
        return new ViewHolder(view);
    }

    // binds the data to the TextView in each row
    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        String animal = mData.get(position);
        holder.myTextView.setText(animal);
    }

    // total number of rows
    @Override
    public int getItemCount() {
        return mData.size();
    }

    // stores and recycles views as they are scrolled off screen
    public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
        TextView myTextView;

        ViewHolder(View itemView) {
            super(itemView);
            myTextView = itemView.findViewById(R.id.tvStationName);
            itemView.setOnClickListener(this);
        }

        @Override
        public void onClick(View view) {
            if (mClickListener != null) mClickListener.onItemClick(view, getAdapterPosition());
        }
    }

    // convenience method for getting data at click position
    public String getItem(int id) {
        return mData.get(id);
    }

    // allows clicks events to be caught
    public void setClickListener(ItemClickListener itemClickListener) {
        this.mClickListener = itemClickListener;
    }

    // parent activity will implement this method to respond to click events
    public interface ItemClickListener {
        void onItemClick(View view, int position);
    }
}

line_divider.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">

    <size
        android:width="1dp"
        android:height="1dp" />

    <solid android:color="@color/dark_gray" />

</shape>

radioview_row.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="wrap_content"
    android:orientation="horizontal"
    android:padding="10dp">

    <TextView
        android:id="@+id/tvStationName"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="20sp"/>

</LinearLayout>

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<de.dlyt.yanndroid.oneui.layout.DrawerLayout 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:id="@+id/drawer_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:drawer_icon="@drawable/ic_samsung_settings"
    app:toolbar_title="@string/app_name"
    tools:context=".MainActivity">

    <de.dlyt.yanndroid.oneui.view.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fillViewport="true"
        app:layout_behavior="@string/sesl_appbar_scrolling_view_behavior"
        app:layout_location="main_content">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:animateLayoutChanges="true"
            android:orientation="vertical">

            <!-- Google --><!--
            <androidx.recyclerview.widget.RecyclerView
                android:id="@+id/rvStations"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="@color/item_background_color" />
            -->
            <!-- Samsung -->
            <de.dlyt.yanndroid.oneui.view.RecyclerView
                android:id="@+id/rvStations"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="?android:attr/selectableItemBackground" />

        </LinearLayout>

    </de.dlyt.yanndroid.oneui.view.NestedScrollView>

    <include
        android:id="@+id/viewInDrawer"
        layout="@layout/drawer_content" />

</de.dlyt.yanndroid.oneui.layout.DrawerLayout>

Screenshot_20220508-210612_Internet Radio

salvogiangri commented 2 years ago

To add the ripple effect for each item in the list, the item must have both a click listener set and a ripple background (you must use the bg in the parent LinearLayout of radioview_row instead of RecyclerView itself). Regarding the rounded corners, they must be implemented manually inside the ItemDecoration. Since you've already enabled seslSetLastRoundedCorner in the recyclerView itself, and since your list doesn't have any kind of separator view type, you can simply add the missing top corners in the ItemDecoration like this:

public class SimpleDividerItemDecoration extends RecyclerView.ItemDecoration {
    private Drawable mDivider;
    private SeslRoundedCorner mListRoundedCorner;

    public SimpleDividerItemDecoration(Context context) {
        mDivider = ContextCompat.getDrawable(context, R.drawable.line_divider);
        mListRoundedCorner = new SeslRoundedCorner(context);
        mListRoundedCorner.setRoundedCorners(SeslRoundedCorner.ROUNDED_CORNER_TOP_LEFT | SeslRoundedCorner.ROUNDED_CORNER_TOP_RIGHT);
    }

    @Override
    public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
        int left = parent.getPaddingLeft();
        int right = parent.getWidth() - parent.getPaddingRight();

        int childCount = parent.getChildCount();
        for (int i = 0; i < childCount; i++) {
            View child = parent.getChildAt(i);

            RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();

            int top = child.getBottom() + params.bottomMargin;
            int bottom = top + mDivider.getIntrinsicHeight();

            mDivider.setBounds(left, top, right, bottom);
            mDivider.draw(c);
        }
    }

    @Override
    public void seslOnDispatchDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
        mListRoundedCorner.drawRoundedCorner(c);
    }

    /*
    public void setDivider(Drawable d) {
        mDivider = d;
        mDividerHeight = d.getIntrinsicHeight();
        listView.invalidateItemDecorations();
    }
     */
}
veso266 commented 2 years ago

Wohoo, thanks, that did it Screenshot_20220508-221039_Internet Radio

for some reson I am still not able to set the bottom color right

        recyclerView.seslSetFillBottomEnabled(true);
        recyclerView.seslSetFillBottomColor(R.color.background);

do you maybe know how this color is called (so it will stay right in light/dark theme) (the one on the background on the top (where it says Internet radio)

I also tried like this

recyclerView.seslSetFillBottomColor(de.dlyt.yanndroid.oneui.R.color.background_color);

but color stays the same regardles and for some readon does not match the background

salvogiangri commented 2 years ago

You don't need to use a custom color for the fill bottom feature since it will always use the same color as the rounded corners/bg one (R.color.background_color). If you instead want to apply the color of your items (R.color.item_background_color) then just disable both fillBottom and lastRoundedCorner in your RecyclerView

veso266 commented 2 years ago

Thanks

recyclerView.seslSetFillBottomEnabled(true);

without setting

recyclerView.seslSetFillBottomColor(R.color.background);

did it just fine, now its perfect Screenshot_20220508-223635_Internet Radio