I'm having the usual problem with a list + a RecyclerView: when I change the resource file of an item (aka: selected/unselected star icon) and then scroll, other items of the list are keeping the same selected/unselected state for their own star. Plus, when I select an item and then go back, I'm missing the selected/unselected state.
The fullStar and the emptyStar are simple Android Vector images.
Here it is my ListFragment:
public class PetrolStationListFragment extends Fragment {
private RecyclerView mPetrolStationRecyclerView;
private PetrolStationAdapter mAdapter;
private int itemPosition;
public static boolean toBeCreated;
private static final String ARG_POSITION = "position";
// Design pattern to instantiate a new fragment.
public static PetrolStationListFragment newInstance(int position) {
PetrolStationListFragment fragment = new PetrolStationListFragment();
Bundle args = new Bundle();
args.putInt(ARG_POSITION, position);
fragment.setArguments(args);
return fragment;
}
/********************************************************/
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_petrol_station_list, container, false);
mPetrolStationRecyclerView = (RecyclerView) view.findViewById(R.id.petrol_recycler_view);
mPetrolStationRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
updateUI();
return view;
}
#Override
public void onResume() {
super.onResume();
updateUI();
}
private void updateUI() {
PetrolStationDAO petrolStationDAO = PetrolStationDAO.get(getActivity());
List<PetrolStation> petrolStations = petrolStationDAO.getPetrolStations();
if (mAdapter == null || toBeCreated) {
mAdapter = new PetrolStationAdapter(petrolStations);
mPetrolStationRecyclerView.setAdapter(mAdapter);
toBeCreated = false;
} else {
mAdapter.notifyItemChanged(itemPosition);
}
}
private class PetrolStationHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
private PetrolStation mPetrolStation;
private TextView mNameTextView;
private TextView mAddressTextView;
private TextView mDistanceTextView;
private AppCompatImageView mStar;
private boolean mFavourite;
public PetrolStationHolder(View itemView) {
super(itemView);
itemView.setOnClickListener(this);
mNameTextView = (TextView) itemView.findViewById(R.id.list_item_station_name_text_view);
mAddressTextView = (TextView) itemView.findViewById(R.id.list_item_station_address_text_view);
mDistanceTextView = (TextView) itemView.findViewById(R.id.list_item_station_distance_text_view);
mStar = (AppCompatImageView) itemView.findViewById(R.id.list_item_station_star_image_view);
mStar.setTag(R.id.list_item_station_star_image_view, "emptyStar");
}
public void bindPetrolStation(PetrolStation petrolStation) {
mPetrolStation = petrolStation;
mNameTextView.setText(mPetrolStation.getName());
mAddressTextView.setText("Via Verdi, 19/A");
mDistanceTextView.setText("300 meters");
mFavourite = mPetrolStation.isFavourite(mStar);
Log.d("FAVOURITE", "mFavourite: " + mFavourite);
//setStarByBoolean();
mStar.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
setStarByTag();
}
});
}
#Override
public void onClick(View v) {
//itemPosition = mPetrolStationRecyclerView.getChildAdapterPosition(v);
Intent intent = PetrolStationPagerActivity.newIntent(getActivity(), mPetrolStation.getId());
startActivity(intent);
}
public void setStarByBoolean() {
if (!mFavourite) {
mStar.setImageResource(R.drawable.ic_star_border_orange);
mStar.setTag(R.id.list_item_station_star_image_view, "emptyStar");
} else {
mStar.setImageResource(R.drawable.ic_star_orange);
mStar.setTag(R.id.list_item_station_star_image_view, "fullStar");
}
}
public void setStarByTag() {
if (mStar.getTag(R.id.list_item_station_star_image_view).equals("emptyStar")) {
mStar.setImageResource(R.drawable.ic_star_orange);
mStar.setTag(R.id.list_item_station_star_image_view, "fullStar");
} else {
mStar.setImageResource(R.drawable.ic_star_border_orange);
mStar.setTag(R.id.list_item_station_star_image_view, "emptyStar");
}
}
}
private class PetrolStationAdapter extends RecyclerView.Adapter<PetrolStationHolder> {
private List<PetrolStation> mPetrolStations;
public PetrolStationAdapter(List<PetrolStation> petrolStations) {
mPetrolStations = petrolStations;
}
#Override
public PetrolStationHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater layoutInflater = LayoutInflater.from(getActivity());
View view = layoutInflater.inflate(R.layout.list_item_petrol_station, parent, false);
return new PetrolStationHolder(view);
}
#Override
public void onBindViewHolder(PetrolStationHolder holder, int position) {
PetrolStation petrolStation = mPetrolStations.get(position);
Log.d("POSITION", "position: " + position);
holder.bindPetrolStation(petrolStation);
}
#Override
public int getItemCount() {
return mPetrolStations.size();
}
}
}
And here a the getter and the setter for the PetrolStation Model class:
public boolean isFavourite(AppCompatImageView star) {
if (star.getTag(R.id.list_item_station_star_image_view).equals("emptyStar")) {
mFavourite = false;
} else {
mFavourite = true;
}
return mFavourite;
}
public void setFavourite(boolean favourite) {
this.mFavourite = favourite;
}
Any hint about how to fix this issue? I'm finding difficult to apply the CheckBoxes examples I've found to my own case.
Related
I have a test application.
The questions is uploaded to ViewPager. Each Viewpager element is a fragment. On the fragment there is TextView for question text and RecyclerView for answer options.
I need a button to appear when I select the answer option for the main activity. When you click on the button, the answers should be highlighted in red or green.
I can not understand how to implement the latter. How can I change the colour of a RecyclerView item from Activity?
The code allows you to select one or more options and highlight them.
My java classes:
public class QuestionActivity extends DaggerAppCompatActivity implements View.OnClickListener {
private QuestionViewModel viewModel;
private ViewPager questionsViewPager;
private TabLayout questionTabs;
private ProgressBar progressBar;
private TextView questionNumber;
private FloatingActionButton submitButton;
private OnQuestionListener onQuestionListener;
#Inject
ViewModelProviderFactory providerFactory;
#Inject
QuestionAdapter questionAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
AndroidInjection.inject(this);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_question);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
questionsViewPager = findViewById(R.id.questionViewPager);
questionTabs = findViewById(R.id.questionTabLayout);
progressBar = findViewById(R.id.loadQuestionsProgressBar);
questionNumber = findViewById(R.id.questionNumberTextView);
submitButton = findViewById(R.id.submitFloatingActionButton);
onQuestionListener = questionAdapter;
submitButton.setOnClickListener(this);
viewModel = ViewModelProviders.of(this, providerFactory).get(QuestionViewModel.class);
Intent intent = getIntent();
Theme theme = intent.getParcelableExtra(Constants.THEME);
int themeId = theme.getThemeId();
initQuestionViewPager();
subscribeObservers(themeId);
}
#Override
public void onBackPressed() {
navThemeScreen();
}
#Override
public boolean onOptionsItemSelected(#NonNull MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
navThemeScreen();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
private void subscribeObservers(int themeId) {
viewModel.observeQuestions(themeId).observe(this, new Observer<Resource<List<Question>>>() {
#Override
public void onChanged(Resource<List<Question>> listResource) {
if (listResource != null) {
switch (listResource.status) {
case LOADING:
showProgress(true);
break;
case SUCCESS:
questionAdapter.setQuestions(listResource.data);
initTabs();
questionNumber.setText("Вопрос 1 из " + listResource.data.size());
showProgress(false);
break;
case ERROR:
showProgress(false);
Toast.makeText(QuestionActivity.this, listResource.message, Toast.LENGTH_SHORT).show();
}
}
}
});
}
private void initQuestionViewPager() {
questionsViewPager.setAdapter(questionAdapter);
questionsViewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
questionNumber.setText("Вопрос " + Integer.toString(position + 1) + " из " + questionsViewPager.getAdapter().getCount());
}
#Override
public void onPageSelected(int position) {
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
}
private void initTabs() {
questionTabs.setupWithViewPager(questionsViewPager, true);
for (int i = 0; i < questionsViewPager.getAdapter().getCount(); ++i) {
questionTabs.getTabAt(i).setText(Integer.toString(i + 1));
}
}
private void showProgress(boolean show) {
if (show) {
progressBar.setVisibility(View.VISIBLE);
}
else {
progressBar.setVisibility(View.GONE);
}
}
private void navThemeScreen() {
Intent intent = new Intent(QuestionActivity.this, ThemeActivity.class);
startActivity(intent);
finish();
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.submitFloatingActionButton:
onQuestionListener.onSubmitClick(questionsViewPager.getCurrentItem());
}
}
public interface OnQuestionListener {
void onSubmitClick(int questionNumber);
}
}
Fragment:
public class QuestionFragment extends Fragment implements View.OnClickListener,
OptionViewHolder.OnOptionListener, QuestionActivity.OnQuestionListener {
private View view;
private TextView questionText;
private RecyclerView options;
private FloatingActionButton submitButton;
private ViewPager viewPager;
private SingleQuestionViewModel viewModel;
private int position;
private Question question;
#Inject
ViewModelProviderFactory providerFactory;
#Inject
OptionAdapter optionAdapter;
public static QuestionFragment newInstance(int position) {
QuestionFragment fragment = new QuestionFragment();
Bundle args = new Bundle();
args.putInt("position", position);
fragment.setArguments(args);
return fragment;
}
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
view = inflater.inflate(R.layout.fragment_question, container, false);
viewPager = (ViewPager) container;
position = getArguments().getInt("position");
return view;
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
AndroidSupportInjection.inject(this);
questionText = view.findViewById(R.id.questionTextTextView);
options = view.findViewById(R.id.optionsRecyclerView);
submitButton = view.findViewById(R.id.submitFloatingActionButton);
submitButton.setOnClickListener(this);
viewModel = ViewModelProviders.of(this, providerFactory).get(SingleQuestionViewModel.class);
question = viewModel.getQuestion(position);
initQuestion();
initOptions();
}
private void initQuestion() {
questionText.setText(question.getText());
}
private void initOptions() {
if (question.isMultipleAnswer()) {
optionAdapter.setMultiSelectionEnabled(true);
}
optionAdapter.setOptions(question.getOptions());
optionAdapter.setOnOptionListener(this);
options.setAdapter(optionAdapter);
options.setLayoutManager(new LinearLayoutManager(view.getContext()));
options.setHasFixedSize(true);
}
#SuppressLint("RestrictedApi")
private void showSubmitButton(boolean show) {
if (show) {
submitButton.setVisibility(View.VISIBLE);
}
else {
submitButton.setVisibility(View.GONE);
}
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.submitFloatingActionButton:
boolean isCorrect = question.checkAnswers();
int currPos = viewPager.getCurrentItem();
new Handler().post(() -> viewPager.setCurrentItem(currPos + 1, true));
break;
}
}
#Override
public void onOptionSelected(OptionViewHolder v, SelectedOption selectedOption) {
}
#Override
public void onSubmitClick(int questionNumber) {
RecyclerView.ViewHolder test = options.getChildViewHolder(options.getChildAt(0));
optionAdapter.selectCorrectOptions();
}
class AnswerTask extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... voids) {
question.setAnswers(optionAdapter.getSelectedOptions());
showSubmitButton(true);
return null;
}
}
}
Page adapter
public class QuestionAdapter extends FragmentStatePagerAdapter implements QuestionActivity.OnQuestionListener {
private List<Question> questions;
private HashMap<Integer, WeakReference<Fragment>> fragments;
private QuestionActivity.OnQuestionListener onQuestionListener;
public QuestionAdapter(#NonNull FragmentManager fm, int behavior) {
super(fm, behavior);
questions = new ArrayList<>();
}
#Override
public int getCount() {
return questions.size();
}
public void setQuestions(List<Question> questions) {
this.questions = questions;
fragments = new HashMap<>();
notifyDataSetChanged();
}
#NonNull
#Override
public Fragment getItem(int position) {
QuestionFragment fragment = new QuestionFragment().newInstance(position);
onQuestionListener = fragment;
return fragment;
}
#Override
public void destroyItem(#NonNull ViewGroup container, int position, #NonNull Object object) {
}
#NonNull
#Override
public Object instantiateItem(#NonNull ViewGroup container, int position) {
Fragment fragment = (Fragment) super.instantiateItem(container, position);
fragments.put(position, new WeakReference<>(fragment));
return fragment;
}
#Override
public void onSubmitClick(int questionNumber) {
onQuestionListener.onSubmitClick(questionNumber);
}
}
RecyclerViewAdpater
public class OptionAdapter extends RecyclerView.Adapter<OptionViewHolder> implements OptionViewHolder.OnOptionListener {
private List<SelectedOption> options;
private LayoutInflater layoutInflater;
private OptionViewHolder.OnOptionListener onOptionListener;
private boolean isMultiSelectionEnabled;
private HashMap<Integer, OptionViewHolder> holders;
public OptionAdapter() {
options = new ArrayList<>();
holders = new HashMap<>();
isMultiSelectionEnabled = false;
}
public void setOptions(List<Option> options) {
this.options.clear();
for(Option option : options) {
this.options.add(new SelectedOption(option, false));
}
notifyDataSetChanged();
}
public void setOnOptionListener(OptionViewHolder.OnOptionListener onOptionListener) {
this.onOptionListener = onOptionListener;
}
public void setMultiSelectionEnabled(boolean multiSelectionEnabled) {
isMultiSelectionEnabled = multiSelectionEnabled;
}
#NonNull
#Override
public OptionViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
layoutInflater = LayoutInflater.from(parent.getContext());
View view = layoutInflater.inflate(R.layout.option_item, parent, false);
OptionViewHolder viewHolder = new OptionViewHolder(view, this);
return viewHolder;
}
#Override
public void onBindViewHolder(#NonNull OptionViewHolder holder, int position) {
SelectedOption selectedOption = options.get(position);
holder.optionTextView.setText(selectedOption.getText());
if (isMultiSelectionEnabled) {
TypedValue typedValue = new TypedValue();
holder.optionTextView.getContext().getTheme().resolveAttribute(android.R.attr.listChoiceIndicatorMultiple, typedValue, true);
int checkMarkDrawableResId = typedValue.resourceId;
holder.optionTextView.setCheckMarkDrawable(checkMarkDrawableResId);
}
else {
TypedValue typedValue = new TypedValue();
holder.optionTextView.getContext().getTheme().resolveAttribute(android.R.attr.listChoiceIndicatorSingle, typedValue, true);
int checkMarkDrawableResId = typedValue.resourceId;
holder.optionTextView.setCheckMarkDrawable(checkMarkDrawableResId);
}
holder.selectedOption = selectedOption;
holder.setChecked(holder.selectedOption.isSelected());
holders.put(position, holder);
}
#Override
public int getItemCount() {
return options.size();
}
public List<Option> getSelectedOptions() {
List<Option> selectedOptions = new ArrayList<>();
for (SelectedOption option : options) {
if (option.isSelected()) {
selectedOptions.add(option);
}
}
return selectedOptions;
}
#Override
public int getItemViewType(int position) {
if (isMultiSelectionEnabled) {
return OptionViewHolder.MULTI_SELECTION;
}
else {
return OptionViewHolder.SINGLE_SELECTION;
}
}
#Override
public void onOptionSelected(OptionViewHolder v, SelectedOption selectedOption) {
if (!isMultiSelectionEnabled) {
for (SelectedOption option : options) {
if (!option.equals(selectedOption) && option.isSelected()) {
option.setSelected(false);
}
else if (option.equals(selectedOption) && selectedOption.isSelected()) {
option.setSelected(true);
}
}
}
notifyDataSetChanged();
onOptionListener.onOptionSelected(v, selectedOption);
}
public void selectCorrectOptions() {
for (Map.Entry<Integer, OptionViewHolder> entry : holders.entrySet()) {
entry.getValue().selectCorrectOptions();
}
notifyDataSetChanged();
}
}
ViewHolder
public class OptionViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public static final int SINGLE_SELECTION = 1;
public static final int MULTI_SELECTION = 2;
CheckedTextView optionTextView;
SelectedOption selectedOption;
OnOptionListener onOptionListener;
public OptionViewHolder(#NonNull View itemView, OnOptionListener onOptionListener) {
super(itemView);
this.onOptionListener = onOptionListener;
optionTextView = itemView.findViewById(R.id.optionTextView);
optionTextView.setOnClickListener(this);
}
#Override
public void onClick(View v) {
if (selectedOption.isSelected() && getItemViewType() == MULTI_SELECTION) {
setChecked(false);
}
else {
setChecked(true);
}
onOptionListener.onOptionSelected(this, selectedOption);
}
public void setChecked(boolean checked) {
if (checked) {
optionTextView.setBackgroundColor(Color.parseColor("#66bfe8"));
}
else {
optionTextView.setBackground(null);
}
selectedOption.setSelected(checked);
optionTextView.setChecked(checked);
}
public void selectCorrectOptions() {
if (selectedOption.isSelected() && selectedOption.isCorrect()) {
optionTextView.setBackgroundColor(Color.parseColor("#007f00"));
}
else {
optionTextView.setBackground(null);
}
onOptionListener.onOptionSelected(this, selectedOption);
}
public interface OnOptionListener {
void onOptionSelected(OptionViewHolder v, SelectedOption selectedOption);
}
}
One way to solve this is to pass your item view to activity using interface. With your item view you can set background color or resource of your item.
So update your interface function with new parameter of type view and when you detect selection of item in your activity with interface, save the view reference and when the button is clicked, use that reference to set background.
I am having two fragments side by side in on the MainActivity
LeftFragment has a RecyclerView with colors and I want to set the background color and text on the Right Fragment when tap on any color on the LeftFragment
The app is crashing with the error null object reference error.
Here is my Github Repo. However, adding some code for reference.
Left Fragment
public class LeftFragment extends Fragment {
public LeftFragment() {
// Required empty public constructor
}
public static LeftFragment newInstance() {
return new LeftFragment();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_left, container, false);
// private OnColorChooseListener mOnColorChooseListener;
ArrayList<Color> mColor = new ArrayList<>();
mColor.add(new Color(getResources().getColor(R.color.colorRed), getResources().getString(R.string.red)));
mColor.add(new Color(getResources().getColor(R.color.colorOrange), getResources().getString(R.string.orange)));
mColor.add(new Color(getResources().getColor(R.color.colorYellow), getResources().getString(R.string.yellow)));
mColor.add(new Color(getResources().getColor(R.color.colorLime), getResources().getString(R.string.lime)));
mColor.add(new Color(getResources().getColor(R.color.colorGreen), getResources().getString(R.string.green)));
mColor.add(new Color(getResources().getColor(R.color.colorCyan), getResources().getString(R.string.cyan)));
mColor.add(new Color(getResources().getColor(R.color.colorBlue), getResources().getString(R.string.blue)));
mColor.add(new Color(getResources().getColor(R.color.colorIndigo), getResources().getString(R.string.indigo)));
mColor.add(new Color(getResources().getColor(R.color.colorViolet), getResources().getString(R.string.violet)));
RecyclerView mRecyclerView = view.findViewById(R.id.color_list_view);
RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getActivity());
RecyclerView.Adapter mAdapter = new ColorAdapter(mColor, getActivity());
mRecyclerView.setLayoutManager(mLayoutManager);
mRecyclerView.setAdapter(mAdapter);
return view;
}
}
Right Fragment
public class RightFragment extends Fragment {
ColorAdapter colorAdapter;
ArrayList<Color> color;
public RightFragment() {
// Required empty public constructor
}
public static RightFragment newInstance() {
return new RightFragment();
}
#Override
public View onCreateView(
LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState
) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_right, container, false);
final ConstraintLayout constraintLayout = view.findViewById(R.id.right_color_block);
final TextView textView = view.findViewById(R.id.right_color_text);
colorAdapter.SetItemClickListener(new ColorAdapter.OnItemClickListener() {
#Override
public void OnItemClick(int position) {
constraintLayout.setBackgroundColor(color.get(position).getmColor());
textView.setText(color.get(position).getmLabel());
}
});
return view;
}
}
ColorAdaptor (RecyclerView)
public class ColorAdapter extends RecyclerView.Adapter<ColorAdapter.ColorViewHolder> {
private List<Color> mColor;
private Context mContext;
private OnItemClickListener mOnItemClickListener;
public ColorAdapter(List<Color> mColor, Context mContext) {
this.mColor = mColor;
this.mContext = mContext;
}
public void SetItemClickListener(OnItemClickListener listener) {
this.mOnItemClickListener = listener;
}
#NonNull
#Override
public ColorViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.color_list_item, viewGroup, false);
return new ColorViewHolder(view, mOnItemClickListener);
}
#Override
public void onBindViewHolder(#NonNull final ColorViewHolder colorViewHolder, final int i) {
final Color color = mColor.get(i);
colorViewHolder.itemColorText.setText(color.getmLabel());
colorViewHolder.itemColorText.setBackgroundColor(color.getmColor());
colorViewHolder.itemColorText.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(mContext, "Item clicked: " + i, Toast.LENGTH_SHORT).show();
// colorViewHolder.feedbackBlock.setBackgroundColor(color.getmColor());
colorViewHolder.feedbackText.setText(color.getmLabel());
}
});
}
#Override
public int getItemCount() {
return mColor.size();
}
public interface OnItemClickListener {
void OnItemClick(int position);
}
class ColorViewHolder extends RecyclerView.ViewHolder {
public ConstraintLayout itemColorBlock;
public TextView itemColorText;
public ConstraintLayout feedbackBlock;
public TextView feedbackText;
public ColorViewHolder(#NonNull View itemView, final OnItemClickListener listener) {
super(itemView);
itemColorBlock = itemView.findViewById(R.id.color_block);
itemColorText = itemView.findViewById(R.id.color_text);
feedbackBlock = itemView.findViewById(R.id.right_color_block);
feedbackText = itemView.findViewById(R.id.right_color_text);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (listener != null) {
int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION) {
listener.OnItemClick(position);
}
}
}
});
}
}
}
Color
public class Color {
private int mColor;
private String mLabel;
public Color(#ColorInt int color, String label) {
this.mColor = color;
this.mLabel = label;
}
public String getmLabel() {
return mLabel;
}
public void setmLabel(String mLabel) {
this.mLabel = mLabel;
}
public int getmColor() {
return mColor;
}
public void setmColor(#ColorInt int mColor) {
this.mColor = mColor;
}
#NonNull
#Override
public String toString() {
return super.toString();
}
}
MainActivity
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
LeftFragment leftFragment = LeftFragment.newInstance();
getSupportFragmentManager().beginTransaction().replace(R.id.left_container, leftFragment).commit();
RightFragment rightFragment = RightFragment.newInstance();
getSupportFragmentManager().beginTransaction().replace(R.id.right_container, rightFragment).commit();
}
}
Your App Crash on RightFragment.class because you are calling colorAdapter.SetItemClickListener (on line 43) as in **RightFragment colorAdapteris null **, you are setting adapter on the different fragment and implementing a listener on different so that's why this crash happens.
You can apply this listener on LeftFragment (where you originally set adapter) and on click of that(in listener callback) you can open right fragment ( send selected data from LeftFragment to RightFragment), This SO Answer can help you in this , when right fragment open you will get selected color data and here you can use it on RightFragment.
I'm having a problem with assigning onclicklistener to recyclerview items.
When I click the item, first click is ignored and listener doesn't run.
I mean, I have to click once, and then again to run the listener.
Once it runs, listener works well.
here is my code.
public class BoardFragment extends Fragment {
//recycler view ingredient
private RecyclerView recyclerView_board;
public static board_adapter mboard_adapter;
public static ArrayList<board_item> board_itemList;
private RecyclerView.LayoutManager board_LayoutManager;
//recycler view ingredient end
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View v = inflater.inflate(fragment_board, container, false);
//recycler view setting
recyclerView_board = (RecyclerView) v.findViewById(R.id.board_recycler);
board_itemList = new ArrayList<board_item>();
board_LayoutManager = new LinearLayoutManager(getActivity());
mboard_adapter = new board_adapter(board_itemList);
recyclerView_board.setAdapter(mboard_adapter);
recyclerView_board.setLayoutManager(board_LayoutManager);
recyclerView_board.setItemAnimator(new DefaultItemAnimator());
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(recyclerView_board.getContext(), DividerItemDecoration.VERTICAL);
recyclerView_board.addItemDecoration(dividerItemDecoration);
board_item item = new board_item();
item.setName("Hello");
board_itemList.add(item);
mboard_adapter.notifyDataSetChanged();
//recycler view setting end
return v;
}
public static class board_item {
private String name;
private CheckBox button;
private int state = 0;
public String getName() {
return this.name;
}
public CheckBox getButton() {
return this.button;
}
public int getState() {
return this.state;
}
public void setName(String name) {
this.name = name;
}
public void setButton(CheckBox button) {
this.button = button;
}
public void setState(int state) {
this.state = state;
}
}
public class board_adapter extends RecyclerView.Adapter<board_adapter.ViewHolder> {
private ArrayList<board_item> temp_board_array;
public board_adapter(ArrayList<board_item> board_itemList) {
temp_board_array = board_itemList;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.recyclerview_item_board, parent, false);
view.setOnClickListener(new board_onclick_listener());
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
final int itemposition = position;
holder.board_name_text.setText(temp_board_array.get(position).getName());
class board_button_onclick_listener implements View.OnClickListener {
#Override
public void onClick(final View view) {
board_item item = board_itemList.get(itemposition);
Toast.makeText(view.getContext(), "button clicked", Toast.LENGTH_LONG).show();
if(item.getState() == 0){
}
else {
}
}
}
holder.board_favorite_button.setOnClickListener(new board_button_onclick_listener());
}
#Override
public int getItemCount() {
return temp_board_array.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
public TextView board_name_text;
public CheckBox board_favorite_button;
public ViewHolder(View itemView) {
super(itemView);
board_name_text = (TextView) itemView.findViewById(R.id.board_name);
board_favorite_button = (CheckBox) itemView.findViewById(R.id.board_favorite_button);
}
}
//각 아이템에 적용될 리스너
class board_onclick_listener implements View.OnClickListener {
#Override
public void onClick(final View view) {
int itemposition = recyclerView_board.getChildLayoutPosition(view);
board_item item = board_itemList.get(itemposition);
Toast.makeText(view.getContext(), item.getName() + " selected", Toast.LENGTH_LONG).show();
Intent intent = new Intent(view.getContext(), CardActivity.class);
view.getContext().startActivity(intent);
}
}
}
}
I have two tabs (fragments), NewOrders and FinishedOrders, I'm populating the orders via Volley requests, now each item inside the New Orders tab has a SwipeLayout which show a clickable textview that makes the order finished, and move it to the other tab (backend stuff..), and I got this working perfectly,
The problem is when I click to finish, the recyclerview isn't updated once the request sent successfully, I have to do pull-to-refresh so it would update..! it seems easy to solve, but the issue is handling the swipelayout listener done inside onBindView method inside the adapter..!! that's only place to access it according to the library I'm using (I guess)..! on the other hand refreshing and populating the list happens in the NewOrder tab fragment..!
So how can I make the item to be removed from the list after the click and becomes updated..?!
Any thoughts..!?
My Adapter Class + ViewHolder
Note: the implemented methods in the adapter are required because of the interface of SwipeLayout library
public class OrdersDataAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
implements SwipeAdapterInterface, SwipeItemMangerInterface {
protected SwipeItemRecyclerMangerImpl mItemManger = new SwipeItemRecyclerMangerImpl(this);
public Context context;
ArrayList<OrderPresenter> orders;
public OrdersDataAdapter(ArrayList<OrderPresenter> orders, Context context) {
this.orders = orders;
this.context = context;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.order_card, parent, false);
return new NewOrderVH(v);
}
#Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) {
final OrderPresenter order = this.orders.get(position);
final NewOrderVH vh1 = (NewOrderVH) holder;
vh1.setData(orders.get(position));
mItemManger.bindView(vh1.itemView, position);
vh1.swipeLayout.setShowMode(SwipeLayout.ShowMode.PullOut);
vh1.swipeLayout.addDrag(SwipeLayout.DragEdge.Left,
vh1.swipeLayout.findViewById(R.id.bottom_wrapper));
if (order.isFinished()) {
vh1.swipeLayout.setSwipeEnabled(false);
vh1.setBadge("DONE");
vh1.setBadgeColor(order.getBadgeColor());
} else {
vh1.finish.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// get the clicked item position?
final int position = vh1.getAdapterPosition();
// these responsible for the request which make the order finished
OrderPresenter order = orders.get(position);
OrderRepository.setOrderFinURL(order.getID());
OrderRepository.FinishOrder(order.getID(), context);
/*the commented three lines below didn't help with the problem*/
// notifyItemChanged(position);
// notifyItemRemoved(position);
// notifyDataSetChanged();*/
order.setStatus(order.getStatusText(Order.FINISHED));
}
});
}
}
#Override
public int getItemCount() {
return orders.size();
}
public class NewOrderVH extends RecyclerView.ViewHolder {
SwipeLayout swipeLayout;
private TextView finish;
private CardView orderCard;
TextView Badge;
private ImageView cusPic;
private TextView cusName;
private TextView CusAdress;
private TextView vendorsNum;
private TextView itemsNum;
private TextView time;
private TextView emptyView;
public NewOrderVH(View itemView) {
super(itemView);
Badge = (TextView) itemView.findViewById(R.id.badge);
swipeLayout = (SwipeLayout) itemView.findViewById(R.id.swipe);
finish = (TextView) itemView.findViewById(R.id.finish);
orderCard = (CardView) itemView.findViewById(R.id.OrderCard);
cusPic = (ImageView) itemView.findViewById(R.id.cusPic);
cusName = (TextView) itemView.findViewById(R.id.cusName);
CusAdress = (TextView) itemView.findViewById(R.id.CusAdress);
vendorsNum = (TextView) itemView.findViewById(R.id.vendorsNum);
itemsNum = (TextView) itemView.findViewById(R.id.itemsNum);
time = (TextView) itemView.findViewById(R.id.time);
emptyView = (TextView) itemView.findViewById(R.id.empty_view);
orderCard.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(v.getContext(), OrderDetails.class);
v.getContext().startActivity(intent);
}
});
}
public void setData(final OrderPresenter data) {
time.setText(data.getOrderTime());
cusName.setText(data.getFullName());
vendorsNum.setText(data.getVendorsCount());
itemsNum.setText(data.getItemsCount());
CusAdress.setText(data.getFullAddress());
Picasso.with(context).load(data.getCustomerPicture()).into(cusPic);
}
public void setBadgeColor(int drawable) {
this.Badge.setBackgroundResource(drawable);
}
public void setBadge(String badge) {
this.Badge.setText(badge);
}
}
#Override
public int getSwipeLayoutResourceId(int position) {
return R.id.swipe;
}
#Override
public void openItem(int position) {
}
#Override
public void closeItem(int position) {
}
#Override
public void closeAllExcept(SwipeLayout layout) {
}
#Override
public void closeAllItems() {
}
#Override
public List<Integer> getOpenItems() {
return null;
}
#Override
public List<SwipeLayout> getOpenLayouts() {
return null;
}
#Override
public void removeShownLayouts(SwipeLayout layout) {
}
#Override
public boolean isOpen(int position) {
return false;
}
#Override
public Attributes.Mode getMode() {
return null;
}
#Override
public void setMode(Attributes.Mode mode) {
}
}
My NewOrder Fragment
Note: the FinishedOrders tab (fragment) does the same thing as new order but filters the current the Finished status.
public class NewOrdersTab extends Fragment {
RecyclerView recyclerView;
OrdersDataAdapter adapter;
private SwipeRefreshLayout swiperefresh;
private TextView emptyView;
ArrayList<OrderPresenter> modelData;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final View rootView = inflater.inflate(R.layout.new_orders_tab_frag, container, false);
modelData = new ArrayList<>();
recyclerView = (RecyclerView) rootView.findViewById(R.id.recyclerView);
swiperefresh = (SwipeRefreshLayout) rootView.findViewById(R.id.swiperefresh);
recyclerView.setLayoutManager(new LinearLayoutManager(this.getActivity()));
swiperefresh.setColorSchemeResources(R.color.colorPrimary, R.color.color_error, R.color.colorInfo);
adapter = new OrdersDataAdapter(modelData, getActivity());
emptyView = (TextView) rootView.findViewById(R.id.empty_view);
recyclerView.setAdapter(adapter);
adapter.setMode(Attributes.Mode.Single);
OrderRepository.fetchOrders("awaiting-shipment", getActivity(), new DataFetch() {
#Override
public void onResponse(ArrayList<OrderPresenter> data) {
swiperefresh.setRefreshing(true);
if (data.size() != 0) {
swiperefresh.setRefreshing(true);
emptyView.setVisibility(View.GONE);
modelData.clear();
modelData.addAll(data);
adapter.notifyDataSetChanged();
} else {
emptyView.setVisibility(View.VISIBLE);
emptyView.setText(getString(R.string.No_New_Orders));
}
swiperefresh.setRefreshing(false);
}
});
return rootView;
}
}
I figured it out, I just added these two lines after I make the request..!
orders.remove(position);
notifyItemRemoved(position);
//notifyDataSetChanged(position);
I am using RecycleView to display data, in every ListItem has 3 button: stat_btn, comment_btn and forward_btn. I want to know which button the user clicked to do the different function, so in onClick method , i try to use view.getId() to show which button was clicked, but the view.getId() always return -1;
04-12 10:32:44.273 29382-29382/com.smartspace.magicmirror I/QUESTIONNAIREADAPTER: ---->>view.getid:-1
04-12 10:32:44.273 29382-29382/com.smartspace.magicmirror I/QUESTIONNAIREFRAGMENT: ---->>onItemClick: -1
here is my code:
the adapter
public class QuestionnaireAdapter extends RecyclerView.Adapter<QuestionnaireAdapter.QuestionnaireViewHolder> implements OnClickListener{
private static final String TAG = "QUESTIONNAIREADAPTER";
public Context context;
public Uri picTestUrl = Uri.parse("https://raw.githubusercontent.com/facebook/fresco/gh-pages/static/fresco-logo.png");
public Uri picTestUrl2 = Uri.parse("http://magicwang.oss-cn-qingdao.aliyuncs.com/test.jpg");
private OnRecycleViewItemClickListener mOnItemClickListener = null;
public interface OnRecycleViewItemClickListener {
void onItemClick(View view , String data);
}
public void setOnItemClickListener(OnRecycleViewItemClickListener listener) {
this.mOnItemClickListener = listener;
}
public QuestionnaireAdapter(Context context){
this.context = context;
}
#Override
public QuestionnaireViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.fragment_questionnaire_item, parent, false);
QuestionnaireViewHolder questionnaireViewHolder =
new QuestionnaireViewHolder(view);
view.setOnClickListener(this);
return questionnaireViewHolder;
}
#Override
public void onBindViewHolder(final QuestionnaireViewHolder holder, int position) {
//holder.tv.setText("22");
holder.dressImageView.setImageURI(picTestUrl2);
holder.itemView.setTag("tag");
}
#Override
public int getItemCount() {
return 10;
}
#Override
public void onClick(View v) {
Log.i(TAG,"---->>view.getid:" + v.getId());
if (mOnItemClickListener != null) {
mOnItemClickListener.onItemClick(v,(String)v.getTag());
}
}
ViewHolder
class QuestionnaireViewHolder extends RecyclerView.ViewHolder {
ImageView userIcon;
TextView userName;
TextView questionnaireTime;
SimpleDraweeView dressImageView;
//底部收藏、评论和转发按钮
ImageView starBtn;
ImageView commmentBtn;
ImageView forwardBtn;
public QuestionnaireViewHolder(View itemView) {
super(itemView);
userIcon = (ImageView) itemView.findViewById(R.id.user_icon);
userName = (TextView) itemView.findViewById(R.id.user_name);
questionnaireTime = (TextView) itemView.findViewById(R.id.questionnaire_time);
dressImageView = (SimpleDraweeView) itemView.findViewById(R.id.dress_imageview);
starBtn = (ImageView) itemView.findViewById(R.id.star_btn);
commmentBtn = (ImageView) itemView.findViewById(R.id.comment_btn);
forwardBtn = (ImageView) itemView.findViewById(R.id.forward_btn);
}
}
}
and the Fragment which use the adapter and the recyclerView
public class QuestionnaireFragment extends Fragment {
public static final String TAG = "QUESTIONNAIREFRAGMENT";
// TODO: Customize parameter argument names
private static final String ARG_COLUMN_COUNT = "column-count";
// TODO: Customize parameters
private int mColumnCount = 1;
// private OnListFragmentInteractionListener mListener;
private RecyclerView qusetionnaireRecyclerView;
private QuestionnaireAdapter mQuestionnaireAdapter;
/**
* Mandatory empty constructor for the fragment manager to instantiate the
* fragment (e.g. upon screen orientation changes).
*/
public QuestionnaireFragment() {
}
// TODO: Customize parameter initialization
#SuppressWarnings("unused")
public static QuestionnaireFragment newInstance(int columnCount) {
QuestionnaireFragment fragment = new QuestionnaireFragment();
Bundle args = new Bundle();
args.putInt(ARG_COLUMN_COUNT, columnCount);
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mColumnCount = getArguments().getInt(ARG_COLUMN_COUNT);
}
mQuestionnaireAdapter = new QuestionnaireAdapter(AppApplication.getContext());
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_questionnaireitem_list, container, false);
qusetionnaireRecyclerView = (RecyclerView) view.findViewById(R.id.questionnaire_list);
qusetionnaireRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
qusetionnaireRecyclerView.setAdapter(mQuestionnaireAdapter);
mQuestionnaireAdapter.setOnItemClickListener(new QuestionnaireAdapter.OnRecycleViewItemClickListener() {
#Override
public void onItemClick(View view, String data) {
Log.i(TAG,"---->>onItemClick: " + view.getId());
switch (view.getId()) {
case R.id.star_btn:
//do something
break;
case R.id.comment_btn:
//do something
break;
case R.id.forward_btn:
//do something
break;
}
}
});
return view;
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
}
#Override
public void onDetach() {
super.onDetach();
//mListener = null;
}
}
This is how I would have done it.
Declare the buttons and their id's in the onCreate:
stat = (Button)findViewById(R.id.stat_btn);
cmnt = (Button)findViewById(R.id.comment_btn);
fwd = (Button)findViewById(R.id.forward_btn):
Then define a switch in your onClick method that listens for the button id's
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.stat_btn:
someFunction();
//you can also call Log or Toast here
break;
case R.id.comment_btn:
someFunction2();
break;
case R.id.forward_btn:
someFunction3();
break;
}
}
Add OnClickListeners to the buttons in onBindViewHolder()
#Override
public void onBindViewHolder(final QuestionnaireViewHolder holder, int position) {
//holder.tv.setText("22");
holder.dressImageView.setImageURI(picTestUrl2);
holder.itemView.setTag("tag");
holder.starBtn.setOnClickListener(new OnClickListener()....);
holder.commmentBtn.setOnClickListener(new OnClickListener()....);
holder.forwardBtn.setOnClickListener(new OnClickListener()....);
}
No need to implement OnItemClickListener if you want to listen to only child views and not whole item.