Closed veso266 closed 2 years ago
The new oneui-design module should not be confused with the old OneUI Design Lib, the new design module is an addition to our new oneui-core libs, and contains for the most part only backported components/widget from the old lib.
ToolbarLayout select mode methods are purely aesthetic and are meant to be a replacement for the Contextual Action Mode you should instead use if you're using the new core libs (you can always use the new design module which has a backported ToolbarLayout compatible with the new core libs, but imho I'd rather use ActionMode), so use those to change the UI of the AppBar depending on what you want to do (show/dismiss the select mode, set the selected items count, show/hide the bottom menu bar etc.). The item selection code however must be coded by you, the code in our Sample app is decent if you want to take a look on how we think you should use the ToolbarLayout select mode. The sesl longPress API's in RecyclerView are instead used to handle the press and hold gestures.
We're sorry if there's still no documentation ready for the new libs but both me and Yann have been extremely busy with other stuff, all the new documentation will be available soon in our new wiki page.
We have 3 libraries in this organization:
This one is a modified androidx and material library, here you will find all the stock components, but themed as oneui.
This is sort of a wrapper for the oneui-core and contains custom classes like ToolbarLayout which are making it easier for dev to make apps. This is also the recommended library to use.
This library is deprecated and is replaced by oneui-design, but it still supports oneui 3
We haven't added the action (aka select) and search mode the new sample app but the library does have it. But you can check the old wiki and sample for how to use it (Only difference might be method names, ex: selectmode -> actionmode).
(I see @BlackMesa123 was faster for responding but I'll post it anyway)
(I see @BlackMesa123 was faster for responding but I'll post it anyway)
You had to, couldn't explain it better than you did😂
what is showSelectModeBottomBar(false); suppose to do
This only exist in the old lib I think, and what it does is disable the BottomBar. So if you don't want to show a BottomBar when the SelectMode is enabled you use this. (Honestly I don't remember why I added this😅)
I don't realy know how you then handle back button press
It should be handled automatically be the ToolbarLayout. (see here)
This only exist in the old lib I think, and what it does is disable the BottomBar. So if you don't want to show a BottomBar when the SelectMode is enabled you use this. (Honestly I don't remember why I added this😅)
I think I've added it somewhere in-between 2.3.0 and 2.4.0, to simulate the bottom bar behavior in Samsung apps (it shows when the longpress listener onEnd method is called), but the default behavior of the bottom bar is the same as it always have been
Thanks guys for all this, wiki comes when it comes, but we still have the old wiki so :smile: there is documentation
since my app is coded in the old lib, I guess will just have to make multiselect work somehow (easier to swich libs completly because of a feature :smile:)
Ah, some small progress I was kinda able to make multiselect mode work
//Handle click events
adapter.setOnItemClickListener(new DevicesAdapter.ClickListener() {
String TAG = "clicky";
@Override
public void onItemClick(View v, int position) {
Log.d(TAG, "Click: " + adapter.getItem(position));
if (mSelecting) toggleItemSelected(position);
//Toast.makeText(this, "You clicked " + adapter.getItem(position) + " on row number " + position, Toast.LENGTH_SHORT).show();
}
@Override
public void onItemLongClick(View v, int position) {
Log.d(TAG, "Long Click");
//Toast.makeText(this, "You long clicked " + adapter.getItem(position) + " on row number " + position, Toast.LENGTH_SHORT).show();
if (!mSelecting) setSelecting(true);
toggleItemSelected(position);
rvDevices.seslStartLongPressMultiSelection();
}
});
int selectedElement = -1;
public void setSelecting(boolean enabled) {
if (enabled) {
mSelecting = true;
adapter.notifyItemRangeChanged(0, adapter.getItemCount());
toolbarLayout.setSelectModeBottomMenu(R.menu.select_mode_menu, item -> {
item.setBadge(item.getBadge() + 1);
Toast.makeText(this, "Item: " + item.getTitle() + (String.format(" Ime: %s | IP: %s", adapter.getItem(selectedElement), adapter.getItemDescription(selectedElement))), Toast.LENGTH_SHORT).show();
//Toast.makeText(this, item.getTitle(), Toast.LENGTH_SHORT).show();
return true;
});
toolbarLayout.showSelectMode();
toolbarLayout.setSelectModeAllCheckedChangeListener((buttonView, isChecked) -> {
if (checkAllListening) {
for (int i = 0; i < adapter.getItemCount(); i++) {
selected.put(i, isChecked);
adapter.notifyItemChanged(i);
}
}
int count = 0;
for (Boolean b : selected.values()) if (b) count++;
toolbarLayout.setSelectModeCount(count);
});
//toolbarLayout.showSelectModeBottomBar(false);
} else {
mSelecting = false;
for (int i = 0; i < adapter.getItemCount(); i++) selected.put(i, false);
adapter.notifyItemRangeChanged(0, adapter.getItemCount());
toolbarLayout.setSelectModeCount(0);
toolbarLayout.dismissSelectMode();
}
}
//select mode dismiss on back
@Override
public void onBackPressed() {
if (mSelecting) {
setSelecting(false);
return;
}
else
super.onBackPressed();
Log.d("Button:", "Back button pressed!!");
}
public void toggleItemSelected(int position) {
selected.put(position, !selected.get(position));
adapter.notifyItemChanged(position);
selectedElement = position;
checkAllListening = false;
int count = 0;
for (Boolean b : selected.values()) if (b) count++;
toolbarLayout.setSelectModeAllChecked(count == adapter.getItemCount());
toolbarLayout.setSelectModeCount(count);
checkAllListening = true;
}
it now looks like this
still not able to draw the little checkbox next to the item that is selected, and still not able to reliably get row number that is selected, but it is a start :smile:
Remember you do not necessarily need to call seslStartLongPressMultiSelection in the item long press listener, since this will only work if you have set a long press listener in your RecyclerView with seslSetLongPressMultiSelectionListener. To see an example of what seslLongPressMultiSelect does, open a Samsung app that has a list and scroll the list while pressing and holding an item. The rest seems ok, you just need to adjust your list item view to support a checkbox and polish the code a bit since there's still a lot of the dummy stuff we put in our example code (such as the badge for the bottom menu when an item is clicked), remember to use that just as reference since 90% of the time we code that stuff in rush since we want to just showcase how does it looks
Thanks, its good now :smile:
my row looks like this now
<?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"
android:padding="5dp"
android:background="?android:attr/selectableItemBackground">
<CheckBox
android:id="@+id/selected_checkbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@null"
android:clickable="false"
android:focusable="false"
android:visibility="gone"
android:layout_marginLeft="15dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/device_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:text="Relay"
android:textSize="16dp"
android:textStyle="bold"
android:layout_marginStart="@dimen/sesl_action_bar_content_inset"
app:layout_constraintEnd_toStartOf="@+id/enabled_swich"
app:layout_constraintStart_toEndOf="@+id/selected_checkbox"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/device_ip"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:layout_marginEnd="8dp"
android:text="192.168.88.19"
android:layout_marginStart="@dimen/sesl_action_bar_content_inset"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/enabled_swich"
app:layout_constraintStart_toEndOf="@+id/selected_checkbox"
app:layout_constraintTop_toBottomOf="@id/device_name"
app:layout_constraintVertical_bias="0.0" />
<de.dlyt.yanndroid.oneui.view.Switch
android:id="@+id/enabled_swich"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="2dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/device_ip"
app:layout_constraintTop_toTopOf="parent"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
my events are like this
//Handle click events
adapter.setOnItemClickListener(new DevicesAdapter.ClickListener() {
String TAG = "clicky";
@Override
public void onItemClick(View v, int position) {
Log.d(TAG, "Click: " + adapter.getItem(position));
if (mSelecting) {
toggleItemSelected(position);
selectedElement = position;
}
//Toast.makeText(this, "You clicked " + adapter.getItem(position) + " on row number " + position, Toast.LENGTH_SHORT).show();
}
@Override
public void onItemLongClick(View v, int position) {
Log.d(TAG, "Long Click");
//Toast.makeText(this, "You long clicked " + adapter.getItem(position) + " on row number " + position, Toast.LENGTH_SHORT).show();
if (!mSelecting) setSelecting(true);
toggleItemSelected(position);
selectedElement = position;
rvDevices.seslStartLongPressMultiSelection();
}
});
and my selecting methods
Stack<Integer> selectedStack = new Stack<Integer>(); //This stack ensours that selected elements is always uvailable
public void setSelecting(boolean enabled) {
if (enabled) {
mSelecting = true;
adapter.notifyItemRangeChanged(0, adapter.getItemCount());
toolbarLayout.setSelectModeBottomMenu(R.menu.select_mode_menu, item -> {
Toast.makeText(this, "Item: " + item.getTitle() + (String.format(" Ime: %s | IP: %s", adapter.getItem(selectedStack.peek()), adapter.getItemDescription(selectedStack.peek()))), Toast.LENGTH_SHORT).show();
return true;
});
toolbarLayout.showSelectMode();
toolbarLayout.setSelectModeAllCheckedChangeListener((buttonView, isChecked) -> {
if (checkAllListening) {
for (int i = 0; i < adapter.getItemCount(); i++) {
selected.put(i, isChecked);
adapter.notifyItemChanged(i);
}
}
int count = 0;
for (Boolean b : selected.values()) if (b) count++;
toolbarLayout.setSelectModeCount(count);
});
//toolbarLayout.showSelectModeBottomBar(false);
} else {
mSelecting = false;
for (int i = 0; i < adapter.getItemCount(); i++) selected.put(i, false);
adapter.notifyItemRangeChanged(0, adapter.getItemCount());
toolbarLayout.setSelectModeCount(0);
toolbarLayout.dismissSelectMode();
}
}
//select mode dismiss on back
@Override
public void onBackPressed() {
if (mSelecting) {
setSelecting(false);
return;
}
else
super.onBackPressed();
Log.d("Button:", "Back button pressed!!");
}
public void toggleItemSelected(int position) {
selected.put(position, !selected.get(position));
adapter.notifyItemChanged(position);
if (selected.get(position))
selectedStack.push(position);
else
selectedStack.pop();
checkAllListening = false;
int count = 0;
for (Boolean b : selected.values()) if (b) count++;
toolbarLayout.setSelectModeAllChecked(count == adapter.getItemCount());
toolbarLayout.setSelectModeCount(count);
checkAllListening = true;
}
my deviceAdapter.java
package si.wolf.sonoffc.adapters;
import android.content.Context;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.TextView;
//import androidx.recyclerview.widget.RecyclerView; //Google
import de.dlyt.yanndroid.oneui.view.RecyclerView; //Samsung
import java.util.List;
import de.dlyt.yanndroid.oneui.view.Switch;
import si.wolf.sonoffc.R;
import si.wolf.sonoffc.models.Device;
// Create the basic adapter extending from RecyclerView.Adapter
// Note that we specify the custom ViewHolder which gives us access to our views
public class DevicesAdapter extends RecyclerView.Adapter<DevicesAdapter.ViewHolder> {
// Events
private ClickListener mclickListener;
private ItemCheckChangedListener mCheckChangedListener;
// ... view holder defined above...
// Store a member variable for the contacts
private List<Device> mDevices;
// Pass in the contact array into the constructor
public DevicesAdapter(List<Device> contacts) {
mDevices = contacts;
}
// Provide a direct reference to each of the views within a data item
// Used to cache the views within the item layout for fast access
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener, CompoundButton.OnCheckedChangeListener{
// Your holder should contain a member variable
// for any view that will be set as you render a row
public TextView nameTextView;
public TextView descriptionTextView;
public Switch enabledSwich;
public CheckBox selected_checkbox;
// We also create a constructor that accepts the entire item row
// and does the view lookups to find each subview
public ViewHolder(View itemView) {
// Stores the itemView in a public final member variable that can be used
// to access the context from any ViewHolder instance.
super(itemView);
nameTextView = (TextView) itemView.findViewById(R.id.device_name);
descriptionTextView = (TextView) itemView.findViewById(R.id.device_ip);
enabledSwich = (Switch) itemView.findViewById(R.id.enabled_swich);
selected_checkbox = (CheckBox) itemView.findViewById(R.id.selected_checkbox);
//Events
itemView.setOnLongClickListener(this); // long click should be set up before standard click
itemView.setOnClickListener(this);
}
//Click listener
@Override
public void onClick(View v) {
mclickListener.onItemClick(v, getAdapterPosition());
}
@Override
public boolean onLongClick(View v) {
mclickListener.onItemLongClick(v, getAdapterPosition());
// return false; // fire normal click also
return true;
}
//Check changed listener
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (mCheckChangedListener != null) mCheckChangedListener.onItemCheckedChanged(buttonView, getAdapterPosition());
}
}
// ... constructor and member variables
// Usually involves inflating a layout from XML and returning the holder
@Override
public DevicesAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Context context = parent.getContext();
LayoutInflater inflater = LayoutInflater.from(context);
// Inflate the custom layout
View contactView = inflater.inflate(R.layout.device_row, parent, false);
// Return a new holder instance
ViewHolder viewHolder = new ViewHolder(contactView);
return viewHolder;
}
// Involves populating data into the item through holder
@Override
public void onBindViewHolder(DevicesAdapter.ViewHolder holder, int position) {
// Get the data model based on position
Device device = mDevices.get(position);
// Set item views based on your views and data model
TextView textView_name = holder.nameTextView;
textView_name.setText(device.getName());
TextView textView_description = holder.descriptionTextView;
textView_description.setText(device.getIPAddress());
Switch enabled_switch = holder.enabledSwich;
enabled_switch.setChecked(device.isOnline());
//To implement this outside view here: https://stackoverflow.com/a/49969478/17826480
holder.enabledSwich.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
Log.d("demo", "onChecked: position: " + position + " | name: " + device.getName());
}
});
//Make Selected item have checkbox (yea, I know there is probably a better way then to make mSelecting & selected array static but I don't know it right now :)
holder.selected_checkbox.setVisibility(si.wolf.sonoffc.MainActivity.mSelecting ? View.VISIBLE : View.GONE);
if (si.wolf.sonoffc.MainActivity.mSelecting)
holder.selected_checkbox.setChecked(si.wolf.sonoffc.MainActivity.selected.get(position));
}
// Returns the total count of items in the list
@Override
public int getItemCount() {
return mDevices.size();
}
//Events
// convenience method for getting data at click position
public String getItem(int id) {
return mDevices.get(id).getName();
}
public String getItemDescription(int id) { return mDevices.get(id).getIPAddress(); }
//Click events
// allows clicks events to be caught
// parent activity will implement this method to respond to click events
public void setOnItemClickListener(ClickListener listener) {
mclickListener = listener;
}
public interface ClickListener {
void onItemClick(View v, int position);
void onItemLongClick(View v, int position);
}
// parent activity will implement this method to respond to click events
public interface ItemCheckChangedListener {
void onItemCheckedChanged(View view, int position);
}
}
the animation between android:visibility="gone" and android:visibility="visible" is stil preaty rough but it works its just rough :smile:
even managed to implement the quick multiselection thingy
//Multi selection
rvDevices.seslSetLongPressMultiSelectionListener(new RecyclerView.SeslLongPressMultiSelectionListener() {
@Override
public void onItemSelected(RecyclerView view, View child, int position, long id) {
if (adapter.getItemViewType(position) == 0) {
toggleItemSelected(position);
}
}
@Override
public void onLongPressMultiSelectionStarted(int x, int y) {
//drawerLayout.showSelectModeBottomBar(false);
}
@Override
public void onLongPressMultiSelectionEnded(int x, int y) {
// mHandler.postDelayed(mShowBottomBarRunnable, 300);
}
});
Didn't even know I can do this, so thanks for teaching me that trick, it makes quick selection so much easier
Hello there, I am trying to implement multiSelect on RecycleView on ToolbarLayout, just like in this picture
But I am failing
My selecting methods look like this
I can secsesfully detect short and long clicks with my adapter like so
then in MainActivity onCreate, you bind to them
My view looks like this activity_main.xml
my recycleView row looks like this (probably doesn't matter for multiselect but just in case)
and my bottomBar which I would like to show when multiselecting (select_mode_menu) looks like this
Now I have a bit of trouble, since your I have no idea what theese in setSelecting do (yea, I am trying to adapt from here: https://github.com/OneUIProject/OneUI-Design-Library/blob/062c469b35ce127eeb84c0130725ead7032fc516/app/src/main/java/de/dlyt/yanndroid/oneuiexample/tabs/IconsTab.java#L494
as well as what is showSelectModeBottomBar(false); suppose to do (toolbarLayout, nor Drawer layout seem to have it) and I don't realy know how you then handle back button press
and yea, I am still using the old oneUI library, because it has better documentation and it is the only lib that supports both OneUI3 (which I prefer) and OneUI4 theme
and I still have no idea, why there are 2 libraries https://github.com/OneUIProject/sesl https://github.com/OneUIProject/oneui-design
that both seam to do the same thing (which is better :smile: ?)
Hope you can help me and Thanks for Anwsering and Best Regards