How I could get weekdays with horizontal scroll in recyclerview ?
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.widget_list);
adapter = new MyAdapter(this,getList());
LinearLayoutManager horizontalLayoutManager = new LinearLayoutManager(MainActivity.this, LinearLayoutManager.HORIZONTAL, false);
recyclerView.setLayoutManager(horizontalLayoutManager);
recyclerView.setAdapter(adapter);
recyclerView.addOnItemTouchListener(new RecyclerItemClickListener(this, recyclerView, new RecyclerItemClickListener.OnItemClickListener() {
#Override
public void onItemClick(View view, int position) {
if (isMultiSelect){
//if multiple selection is enabled then select item on single click else perform normal click on item.
multiSelect(position);
}
}
#Override
public void onItemLongClick(View view, int position) {
if (!isMultiSelect){
selectedIds = new ArrayList<>();
isMultiSelect = true;
if (actionMode == null){
actionMode = startActionMode(MainActivity.this); //show ActionMode.
}
}
multiSelect(position);
}
}));
}
private void multiSelect(int position) {
MyData data = adapter.getItem(position);
if (data != null){
if (actionMode != null) {
if (selectedIds.contains(data.getId()))
selectedIds.remove(Integer.valueOf(data.getId()));
else
selectedIds.add(data.getId());
if (selectedIds.size() > 0)
actionMode.setTitle(String.valueOf(selectedIds.size())); //show selected item count on action mode.
else{
actionMode.setTitle(""); //remove item count from action mode.
actionMode.finish(); //hide action mode.
}
adapter.setSelectedIds(selectedIds);
}
}
}
/**
* #see MyData Create dummy List of type MyData.
* #return list
*/
String[] namesOfDays = DateFormatSymbols.getInstance().getShortWeekdays();
private List<MyData> getList(){
List<MyData> list = new ArrayList<>();
list.add(new MyData(1,"Mon"));
list.add(new MyData(2,"Tue"));
list.add(new MyData(3,"Wed"));
list.add(new MyData(4,"Thu"));
list.add(new MyData(5,"Fri"));
list.add(new MyData(6,"Sat"));
list.add(new MyData(7,"Sun"));
return list;
}
#Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
MenuInflater inflater = mode.getMenuInflater();
inflater.inflate(R.menu.menu_select, menu);
return true;
}
#Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
}
#Override
public boolean onActionItemClicked(ActionMode mode, MenuItem menuItem) {
switch (menuItem.getItemId()){
case R.id.action_delete:
//just to show selected items.
StringBuilder stringBuilder = new StringBuilder();
for (MyData data : getList()) {
if (selectedIds.contains(data.getId()))
stringBuilder.append("\n").append(data.getTitle());
}
Toast.makeText(this, "Selected items are :" + stringBuilder.toString(), Toast.LENGTH_SHORT).show();
return true;
}
return false;
}
#Override
public void onDestroyActionMode(ActionMode mode) {
actionMode = null;
isMultiSelect = false;
selectedIds = new ArrayList<>();
adapter.setSelectedIds(new ArrayList<Integer>());
}
Related
I have a RecyclerView list of CardViews. Each CardView has a CheckBox that the user can select/de-select. The initial selection launches a Contextual Action Bar. An ArrayList of Integers is used to hold the checkbox state (selected or un-selected). Scrolling and the checkbox views appear to be working correctly. However, when I click a checkbox to de-select it, it remains checked and another checkbox on a different CardView is de-selected? What am I missing here?
Please note that I do not want to set up a ClickListener in onBindViewHolder.
MainActivity.java
public class MainActivity extends AppCompatActivity implements
RecyclerItemClickListener {
private ArrayList<ListItem> allList;
boolean isMultiSelect = false; // for the Contextual Action Bar status
private ActionMode mActionMode;
ArrayList<ListItem> multiselect_list = new ArrayList<>();
private ArrayList<Integer> checkedListItems = new ArrayList<>();
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
...
// method from the Adapter, the ItemHolder's onClick()
public void onCheckBoxClick(View view, int position) {
if (!isMultiSelect) {
multiselect_list = new ArrayList<>();
isMultiSelect = true;
if (mActionMode == null) {
mActionMode = startSupportActionMode(actionModeCallback);
}
}
multi_select(position);
}
public void multi_select(int position) {
if (mActionMode != null) {
// If a CardView with a CheckBox already selected is clicked on, then the
// Checkbox is unselected, the position is removed from the multiselect_list
// and the size of the list is decremented by +1.
if (multiselect_list.contains(allList.get(position))) {
multiselect_list.remove(allList.get(position));
}
else {
// If an empty CheckBox on a CardView is clicked on, then the position is added to the
// multiselect_list and the size of the list is incremented by +1.
multiselect_list.add(allList.get(position));
}
if (multiselect_list.size() == 1) {
mActionMode.setTitle("1 selected");
}
else if (multiselect_list.size() >= 2) {
mActionMode.setTitle(multiselect_list.size() + " selected");
}
else if (multiselect_list.size() == 0) {
mActionMode.finish();
}
refreshAdapter();
}
}
public void refreshAdapter() {
adapter.selectedItemsList = multiselect_list;
adapter.mListItems = allList;
adapter.notifyDataSetChanged();
}
private ActionMode.Callback actionModeCallback = new ActionMode.Callback() {
Menu context_menu;
#Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
MenuInflater inflater = mode.getMenuInflater();
inflater.inflate(R.menu.menu_action_mode, menu);
context_menu = menu;
return true;
}
...
}
Adapter.java
public class MyRecylerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
public ArrayList<ListItem> mListItems;
private Context mContext;
private RecyclerItemClickListener recyclerItemClickListener;
public ArrayList<ListItem> selectedItemsList = new ArrayList<>();
public MyRecylerAdapter(Context context, ArrayList<ListItem> listItems, ArrayList<ListItem> selectedList) {
this.mContext = context;
this.mListItems = listItems;
this.selectedItemsList = selectedList;
}
private class ItemHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
private CheckBox chkSelected;
private ItemHolder(final View itemView) {
super(itemView);
chkSelected = (CheckBox) itemView.findViewById(R.id.chkSelected);
chkSelected.setOnClickListener(this);
}
public void onClick(View v) {
int adapterPos = getAdapterPosition();
// send data to MainActivity() for starting CAB.
if (recyclerItemClickListener !=null) {
recyclerItemClickListener.onCheckBoxClick(v, adapterPos);
}
if (((CheckBox)v).isChecked()) {
checkedListItems.add(adapterPos);
}
else {
checkedListItems.remove(adapterPos);
}
}
void bind(int position) {
if (checkedListItems.contains(position)) {
chkSelected.setChecked(true);
}
else {
chkSelected.setChecked(false);
}
}
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_contact_item, parent, false);
final ItemHolder itemHolder = new ItemHolder(view);
...
return itemHolder;
}
public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {
final ListItem listItem = mListItems.get(position);
final ItemHolder itemHolder = (ItemHolder) holder;
itemHolder.bind(position);
...
}
In Adpater declare an ArrayList of integers
ArrayList<Integer> checkedItems = new ArrayList();
And in bind function
void bind(int position) {
if (checkedItems.contains(position)) {
chkSelected.setChecked(true);
}
else {
chkSelected.setChecked(false);
}
}
In OnBindviewholder add below code
CompoundButton.OnCheckedChangeListener onCheckedChangeListener = new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
int adapterPos = getAdapterPosition();
if(isChecked) {
checkedItems.add(Integer.valueOf(adapterPos));
}else {
checkedItems.remove(Integer.valueOf(adapterPos));
}
}
}
I want to get all the selected values in TreeView containing CheckBoxTreeItems.
How to accomplish this?
You can listen to the events on the root to keep a Set<TreeItem> up to date or you can do a DFS for selected items starting at the root.
Note that the DFS approach certainly requires the smaller amount of code, but the other approach allows you to keep the set up to date during modifications...
#Override
public void start(Stage primaryStage) {
CheckBoxTreeItem<String> root = new CheckBoxTreeItem<>("root");
CheckBoxTreeItem<String> c1 = new CheckBoxTreeItem<>("c1");
c1.getChildren().addAll(
new CheckBoxTreeItem<>("c1.1"),
new CheckBoxTreeItem<>("c1.2"),
new CheckBoxTreeItem<>("c1.3")
);
CheckBoxTreeItem<String> c2 = new CheckBoxTreeItem<>("c2");
c2.getChildren().addAll(
new CheckBoxTreeItem<>("c2.1"),
new CheckBoxTreeItem<>("c2.2"),
new CheckBoxTreeItem<>("c2.3")
);
CheckBoxTreeItem<String> c3 = new CheckBoxTreeItem<>("c3");
c3.getChildren().addAll(
new CheckBoxTreeItem<>("c3.1"),
new CheckBoxTreeItem<>("c3.2"),
new CheckBoxTreeItem<>("c3.3")
);
root.getChildren().addAll(c1, c2, c3);
TreeView<String> treeView = new TreeView<>(root);
treeView.setCellFactory(CheckBoxTreeCell.forTreeView());
Set<TreeItem<String>> selected = new HashSet<>();
// listen for selection change
root.addEventHandler(CheckBoxTreeItem.checkBoxSelectionChangedEvent(), (CheckBoxTreeItem.TreeModificationEvent<String> evt) -> {
CheckBoxTreeItem<String> item = evt.getTreeItem();
if (evt.wasIndeterminateChanged()) {
if (item.isIndeterminate()) {
selected.remove(item);
} else if (item.isSelected()) {
selected.add(item);
}
} else if (evt.wasSelectionChanged()) {
if (item.isSelected()) {
selected.add(item);
} else {
selected.remove(item);
}
}
});
// listen for subtree add/remove
root.addEventHandler(TreeItem.childrenModificationEvent(), (TreeItem.TreeModificationEvent<String> evt) -> {
if (evt.wasAdded()) {
for (TreeItem<String> added : evt.getAddedChildren()) {
addSubtree(selected, (CheckBoxTreeItem<String>) added);
}
}
if (evt.wasRemoved()) {
for (TreeItem<String> removed : evt.getRemovedChildren()) {
removeSubtree(selected, (CheckBoxTreeItem<String>) removed);
}
}
});
Button button = new Button("print selected");
button.setOnAction(evt -> {
System.out.println("----------------");
selected.stream().map(TreeItem::getValue).forEach(System.out::println);
});
Button button2 = new Button("print dfs");
button2.setOnAction(evt -> {
System.out.println("----------------");
print(root);
});
Button remove = new Button("remove");
remove.setOnAction(evt -> {
root.getChildren().remove(c3);
});
Scene scene = new Scene(new VBox(treeView, button, button2, remove));
primaryStage.setScene(scene);
primaryStage.show();
}
private static <T> void removeSubtree(Collection<TreeItem<T>> collection, CheckBoxTreeItem<T> item) {
if (item.isSelected()) {
collection.remove(item);
} else if (!item.isIndeterminate() && !item.isIndependent()) {
return;
}
for (TreeItem<T> child : item.getChildren()) {
removeSubtree(collection, (CheckBoxTreeItem<T>) child);
}
}
private static <T> void addSubtree(Collection<TreeItem<T>> collection, CheckBoxTreeItem<T> item) {
if (item.isSelected()) {
collection.add(item);
} else if (!item.isIndeterminate() && !item.isIndependent()) {
return;
}
for (TreeItem<T> child : item.getChildren()) {
addSubtree(collection, (CheckBoxTreeItem<T>) child);
}
}
private static <T> void print(CheckBoxTreeItem<T> item) {
if (item.isSelected()) {
System.out.println(item.getValue());
} else if (!item.isIndeterminate() && !item.isIndependent()) {
return;
}
for (TreeItem<T> child : item.getChildren()) {
print((CheckBoxTreeItem<T>) child);
}
}
If you're using a TreeView, you can get the item selected like this:
treeView.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<TreeItem<String>>() {
#Override
public void changed(ObservableValue<? extends TreeItem<String>> observable, TreeItem<String> oldValue,
TreeItem<String> newValue) {
System.out.println("The selected item is : "newValue.getValue());
}
});
I can't update listview with custom adapter and database handler.
Items are updated in the database handler, but listview is updated only when I leave the fragment and come back. I would like to see changes just after adding new item.
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.shopping_list_fragment_layout, container, false);
super.onCreate(savedInstanceState);
//// adding an item to itemList
nameTxt = (EditText) view.findViewById(R.id.txtItem);
couponsAmount = 3;
dbHandler = new ShoppingListDatabaseHandler(getActivity());
itemListView = (ListView) view.findViewById(R.id.listViewShoppingItems);
final ShoppingListListAdapter itemAdapter = new ShoppingListListAdapter(getActivity(), ITEMS_DATA);
final ImageButton addBtn = (ImageButton) view.findViewById(R.id.btnAddItem);
addBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view){
ShoppingListItem item = new ShoppingListItem(dbHandler.getItemsCount(), String.valueOf(nameTxt.getText()), 3);
if (!itemExists(item)) {
dbHandler.createItem(item);
//getListView().invalidateViews();
itemAdapter.notifyDataSetChanged(); // TODO: is not updating
Toast.makeText(getActivity(), String.valueOf(nameTxt.getText()) + " has been added", Toast.LENGTH_SHORT).show();
nameTxt.setText("");
return;
}
Toast.makeText(getActivity(), String.valueOf(nameTxt.getText()) + " already exists", Toast.LENGTH_SHORT).show();
nameTxt.setText("");
}
});
if (dbHandler.getItemsCount() != 0){
ITEMS_DATA.addAll(dbHandler.getAllItems());
}
//itemListView.getListView().invalidateViews();
//itemAdapter.notifyDataSetChanged();
itemListView.setAdapter(itemAdapter);
return view;
}
and my adapter:
public class ShoppingListListAdapter extends BaseAdapter {
private Context context;
private final List<ShoppingListItem> Items; // = new ArrayList<ShoppingListItem>();
//Constructor to initialize values
public ShoppingListListAdapter(Context context, List<ShoppingListItem> Items) {
this.context = context;
this.Items = Items;
}
#Override
public int getCount() {
// Number of times getView method call depends upon
return Items.size();
}
#Override
public Object getItem(int position) {
return null;
}
#Override
public long getItemId(int position) {
return 0;
}
// Number of times getView method call depends upon
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View gridView;
if (convertView == null) {
gridView = new View(context);
gridView = inflater.inflate(R.layout.shopping_list_list_item, null);
ShoppingListItem currentItem = Items.get(position);
TextView itemNameTxt = (TextView) gridView.findViewById(R.id.itemName);
itemNameTxt.setText(currentItem.getName());
TextView couponsAmount = (TextView) gridView.findViewById(R.id.couponsAmount);
couponsAmount.setText("-" + currentItem.getCouponsAmount().toString());
}
else {
gridView = (View) convertView;
}
return gridView;
}
}
I tried:
- getListView().invalidateViews();
- adapter.notifyDataSetChanged();
But probably I do sth wrongly, because it is not helping me.
Can you look at my code?
You have added the item to your database, but not to the list used to create the adapter.
ITEM_DATA.add(item):
itemAdapter.notifyDataSetChanged();
I have made a TreeView, represented by a custom cellFactory where each cell is represented by an HBox looking like this.
How can I access the checkbox so that if you check it, a private boolean field in the corresponding EventTreeItem changes it's value?
Code:
public class EventTreeItem extends TreeItem<String>{
SimpleStringProperty item;
boolean important = true;
public EventTreeItem(boolean important, int id){
this.noNode = noNode;
super.setValue(id);
}
public EventTreeItem(){
}
public void setImportant(Boolean important){
this.important = important;
}
}
CellFactory:
public final class CustomTreeCellFactory extends TreeCell<String>{
private TextField textField;
private HBox hBox;
private HBox hBoxLeaf;
public CustomTreeCellFactory(){
try {
hBox = (HBox) FXMLLoader.load(getClass().getResource("/Views/TreCell.fxml"));
} catch (IOException e) {
System.out.println("This didn't work");
e.printStackTrace();
}
try {
hBoxLeaf = (HBox) FXMLLoader.load(getClass().getResource("/Views/TreCellLowestLevel.fxml"));
} catch (IOException e) {
System.out.println("This didn't work");
e.printStackTrace();
}
hBox.setAlignment(Pos.CENTER_LEFT);
hBoxLeaf.setAlignment(Pos.CENTER_LEFT);
}
#Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (item != null) {
EventTreeItem eventTreeItem = (EventTreeItem) getTreeItem();
if (getTreeView().getTreeItemLevel(getTreeItem())==1) {
setGraphic(this.hBox);
((CheckBox) ((HBox)getGraphic()).getChildren().get(3)).setSelected(((EventTreeItem) getTreeItem()).important);
((Label) hBox.getChildren().get(0)).setText(eventTreeItem.noNode.getEntryNumber() + " " + eventTreeItem.noNode.getClass().getName().split("\\.")[3]);
((Label) hBox.getChildren().get(1)).setText(eventTreeItem.noNode.getDate().toString());
}else if (getTreeView().getTreeItemLevel(getTreeItem())==2){
setGraphic(this.hBoxLeaf);
}
} else {
setGraphic(null);
}
}
}
NodeTreeView
public class NodeTreeView implements ChartView{
private FilteredListModel filteredListModel;
TreeItem<String> root;
AnchorPane parent;
TreeView treeView;
public NodeTreeView(FilteredListModel filteredListModel, TabPane tabPane) throws IOException {
this.filteredListModel = filteredListModel;
parent = (AnchorPane) FXMLLoader.load(getClass().getResource("/Views/TryTreeViewInAnchorPane.fxml"));
parent.setVisible(true);
generateTree();
}
private void generateTree() {
this.root = new EventTreeItem();
root.setExpanded(true);
filteredListModel.makeEventNodeArrays().forEach(node->{
EventTreeItem item = new EventTreeItem((EventNoNode) node);
EventTreeItem item2 = new EventTreeItem();
root.getChildren().add(item);
item.getChildren().add(item2);
});
treeView = (TreeView) parent.getChildren().get(0);
treeView.setRoot(root);
treeView.setShowRoot(false);
treeView.setEditable(true);
treeView.setCellFactory(new Callback<TreeView<String>, TreeCell<String>>() {
#Override
public TreeCell<String> call(TreeView<String> param) {
return new CustomTreeCellFactory();
}
});
}
}
You can add a listener to checkbox's selectedProperty in your CustomTreeCellFactory constructor (which is not a factory, btw; you should call it CustomTreeCell instead):
public CustomTreeCellFactory() {
// ...
CheckBox checkbox = ...;
checkbox.selectedProperty().addListener((obs, wasSelected, isSelected) -> {
((EventTreeItem) getTreeItem()).important = isSelected;
});
}
Btw, it is probably a better idea to make the "important" flag be part of the item, i.e. instead of TreeView<String>, you would have TreeView<MyItem> where MyItem is
class MyItem {
String item;
boolean important;
MyItem(String item, boolean important) {
this.item = item;
this.important = important;
}
}
i need help about settings the combobox buttonCell.
I use a combobox that show data from an observable list that contains data from a table with two columns, "Step" and "NextStep" (NextStep contains one item inserted in column Step); what i need to do is to show the combobox listcell with the list of "Step" and the buttoncell with the relative "NextStep". Now, i can see the listcell correctly but my buttoncell is always empty.
The code:
// SET THE VALUE STEP TO THE LISTCELL
comboStatoSuccessivo.setCellFactory(new Callback<ListView<StatoEsiti>, ListCell<StatoEsiti>>() {
#Override public ListCell<StatoEsiti> call(ListView<StatoEsiti> p) {
return new ListCell<StatoEsiti>() {
#Override
protected void updateItem(StatoEsiti t, boolean bln) {
super.updateItem(t, bln);
if(t != null){
setText(t.statoProperty().getValue());
System.out.println("SET PROPERTY " + t.statoProperty().getValue());
} else {
setText(null);
}
}
};
}
});
// SET THE VALUE NEXTSTEP TO THE BUTTONCELL
comboStatoSuccessivo.setButtonCell(new ListCell<StatoEsiti>() {
#Override
protected void updateItem(StatoEsiti t, boolean bln) {
super.updateItem(t, bln);
if (t != null) { <<<<<<<<<<<<<<-------------ALWAYS NULL----WHY??????
setText(t.statoSuccessivoProperty().getValue());
System.out.println("SET PROPERTY BUTTONCELL " + t.statoSuccessivoProperty().getValue());
} else {
setText(null);
System.out.println("SET PROPERTY BUTTONCELL NULL");
}
}
});
Thanks in advance.
I have looked into your use case with the following demo SSCCE code.
It is working as expected, like as when the item is selected from the combobox's dropmenu the buttoncell is updated with related "nextStep":
public class ComboDemo extends Application {
#Override
public void start(Stage primaryStage) {
List<Person> list = new ArrayList<Person>();
list.add(new Person("step 1212", 12));
list.add(new Person("step 4545", 45));
list.add(new Person("step 5656", 56));
list.add(new Person("step 9090", 90));
ComboBox<Person> comboBox = new ComboBox<>(FXCollections.observableList(list));
comboBox.setCellFactory(new Callback<ListView<Person>, ListCell<Person>>() {
#Override
public ListCell<Person> call(ListView<Person> p) {
return new ListCell<Person>() {
#Override
protected void updateItem(Person t, boolean bln) {
super.updateItem(t, bln);
if (t != null) {
setText(t.getStepProperty().getValue());
System.out.println("SET PROPERTY " + t.getStepProperty().getValue());
} else {
setText(null);
}
}
};
}
});
// SET THE VALUE NEXTSTEP TO THE BUTTONCELL
comboBox.setButtonCell(new ListCell<Person>() {
#Override
protected void updateItem(Person t, boolean bln) {
super.updateItem(t, bln);
if (t != null) {
setText(t.getNextStepProperty().getValue().toString());
System.out.println("SET PROPERTY BUTTONCELL " + t.getNextStepProperty().getValue());
} else {
setText(null);
System.out.println("SET PROPERTY BUTTONCELL NULL");
}
}
});
StackPane root = new StackPane();
root.getChildren().add(comboBox);
Scene scene = new Scene(root, 300, 250);
primaryStage.setScene(scene);
primaryStage.show();
}
public static class Person {
private StringProperty stepProperty = new SimpleStringProperty();
private IntegerProperty nextStepProperty = new SimpleIntegerProperty();
public Person(String step, Integer nextStep) {
this.stepProperty.setValue(step);
this.nextStepProperty.setValue(nextStep);
}
public StringProperty getStepProperty() {
return stepProperty;
}
public void setStepProperty(StringProperty stepProperty) {
this.stepProperty = stepProperty;
}
public IntegerProperty getNextStepProperty() {
return nextStepProperty;
}
public void setNextStepProperty(IntegerProperty nextStepProperty) {
this.nextStepProperty = nextStepProperty;
}
}
public static void main(String[] args) {
launch(args);
}
}
Compare it with yours.