У меня работает Адаптер, который отображает список продуктов питания, где пользователь должен ввести соответствующую сумму в тексте редактирования.
Если пользователь нажимает кнопку подтверждения на программной клавиатуре, все в порядке, и адаптер правильно считывает сумму через OnEditorActionListener или даже дополнительный OnFocusChangeListener.
Однако, если пользователь непосредственно нажимает FAB вида,сумма не записывается, поскольку не вызывается ни OnEditorActionListener, ни OnFocusChangeListener.
Как убедиться, что сумма правильно записана в таком очень вероятном случае?
Вот мой код класса адаптера:
public class FoodCalcAdapter extends RecyclerView.Adapter<FoodCalcAdapter.FoodViewHolder> {
class FoodViewHolder extends RecyclerView.ViewHolder implements AdapterView.OnItemSelectedListener {
// The views of the food calc item
private final TextView foodnameView;
private final EditText amountView;
private final Spinner typicalAmountSpinner;
private FoodViewHolder(View itemView) {
super(itemView);
foodnameView = itemView.findViewById(R.id.newmeal_foodname);
typicalAmountSpinner = itemView.findViewById(R.id.newmeal_typicalamountspinner);
amountView = itemView.findViewById(R.id.newmeal_amount);
amountView.setOnEditorActionListener(new TextView.OnEditorActionListener() {
@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if (actionId == EditorInfo.IME_ACTION_DONE) {
int amount = Integer.parseInt(v.getText().toString());
storeAmount(amount);
return true;
}
return false;
}
});
amountView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (!hasFocus) {
String text = ((EditText) v).getText().toString();
int amount = Integer.parseInt(text);
storeAmount(amount);
}
}
});
}
private void storeAmount(int amount) {
// Store the amount in the first spinner item
TypicalAmount typicalAmount = (TypicalAmount) typicalAmountSpinner.getItemAtPosition(0);
typicalAmount.setAmount(amount);
// ... and store it in the food
selectedFood.get(getAdapterPosition()).setAmount(amount);
}
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
// On selecting a spinner item, write amount to amount view ...
TypicalAmount typicalAmount = (TypicalAmount) parent.getItemAtPosition(position);
amountView.setText(String.valueOf(typicalAmount.getAmount()));
// ... and store it as amount in the food
selectedFood.get(getAdapterPosition()).setAmount(typicalAmount.getAmount());
// If a typical amount (position > 0) is selected, we disable entering text,
// if custom amount (position == 0) is selected, we enable entering text
if (position == 0) {
amountView.setEnabled(true);
amountView.selectAll();
} else {
amountView.setEnabled(false);
}
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
// Nothing to do here
}
}
private final LayoutInflater mInflater;
private List<Food> selectedFood; // Cached copy of all selected food items
FoodCalcAdapter(Context context) {
mInflater = LayoutInflater.from(context);
}
@Override
public FoodViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// Create the food calc item
View itemView = mInflater.inflate(R.layout.food_calc_item, parent, false);
return new FoodViewHolder(itemView);
}
@Override
public void onBindViewHolder(FoodViewHolder holder, int position) {
if (selectedFood != null) {
// Get the current food item
Food food = selectedFood.get(position);
// Set the food name
holder.foodnameView.setText(food.getName());
// Create typical amount spinner
List<TypicalAmount> typicalAmounts = new ArrayList<>();
// First entry should always contain the custom amount, which is by default 0 when first used here
typicalAmounts.add(new TypicalAmount(food.getAmount(), null, mInflater.getContext().getString(R.string.newmeal_customamount)));
// Append typical amounts
appendTypicalAmount(typicalAmounts, food.getAmountSmall(), food.getCommentSmall(), mInflater.getContext().getString(R.string.amountsmall_label));
appendTypicalAmount(typicalAmounts, food.getAmountMedium(), food.getCommentMedium(), mInflater.getContext().getString(R.string.amountmedium_label));
appendTypicalAmount(typicalAmounts, food.getAmountLarge(), food.getCommentLarge(), mInflater.getContext().getString(R.string.amountlarge_label));
// Create adapter and add to spinner
ArrayAdapter<TypicalAmount> typicalAmountAdapter = new ArrayAdapter<>(mInflater.getContext(), R.layout.support_simple_spinner_dropdown_item, typicalAmounts);
typicalAmountAdapter.setDropDownViewResource(R.layout.support_simple_spinner_dropdown_item);
holder.typicalAmountSpinner.setOnItemSelectedListener(holder);
holder.typicalAmountSpinner.setAdapter(typicalAmountAdapter);
// Highlight custom amount text to make it easier to edit it
holder.amountView.selectAll();
} else {
// Covers the case no food has been selected (should never happen, we check before)
holder.foodnameView.setText(mInflater.getContext().getString(R.string.newmeal_nofoodselected));
}
}
void setSelectedFood(List<Food> selectedFood) {
this.selectedFood = selectedFood;
}
List<Food> getSelectedFood() {
return selectedFood;
}
private void appendTypicalAmount(List<TypicalAmount> typicalAmounts, int amount, String comment, String defaultComment) {
if (amount > 0) {
typicalAmounts.add(new TypicalAmount(amount, comment, defaultComment));
}
}
// getItemCount() is called many times, and when it is first called,
// allFood has not been updated (means initially, it's null, and we can't return null)
@Override
public int getItemCount() {
if (selectedFood != null)
return selectedFood.size();
else return 0;
}
}
Было предложено получать значения по щелчку FAB, но я не могу понять, как, поскольку FAB создается вне класса Adapter, в окружающем классе Activity, откуда явозникли проблемы с доступом к одному ViwHolders внутри адаптера.Вот код окружающей деятельности:
public class NewMealActivity extends AppCompatActivity {
public static final String INTENT_FOODCALC = "FoodCalc";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_new_meal);
// Create recycler view
RecyclerView recyclerView = findViewById(R.id.recyclerview_newmeal);
final FoodCalcAdapter adapter = new FoodCalcAdapter(this);
recyclerView.setAdapter(adapter);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
// Pass selected food to adapter
List<Food> selectedFood = getIntent().getParcelableArrayListExtra(MainActivity.INTENT_FOODLIST);
adapter.setSelectedFood(selectedFood);
// Floating action button to calculate meal
FloatingActionButton fabCalc = findViewById(R.id.fab_calcmeal);
fabCalc.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(NewMealActivity.this, CalcMealActivity.class);
// Get all selected food, each weighted with its amount
ArrayList<Food> weightedFood = new ArrayList<Food>(adapter.getSelectedFood());
// Set to intent
Intent weightedFoodList = intent.putParcelableArrayListExtra(INTENT_FOODCALC, weightedFood);
// Start activity
startActivity(intent);
}
});
}
}