ListView からユーザー入力を表示および取得するためのカスタム アダプターがあります。リストの行には、TextView、EditText、および Spinner が含まれています。困っているのはスピナーです。このアプリケーションは、競技者の結果がフィニッシュ位置 (EditText に入力) または結果コード (所定の値のセットからスピナーを使用して選択) のいずれかである、セーリング レースの採点に関するものです。私と同じような問題を抱えている人はたくさんいるようですが、ここにいるような人はいません。
問題は、OnItemSelectedListener が特定の状況でのみトリガーされ、トリガーする必要があるたびにトリガーされるわけではなく、対応する EditText にフォーカスがあるかどうか、または別の行の EditText にフォーカスがあるかどうかによって状況が異なることです。
リストが最初に表示されたとき、フォーカスは何も表示されず、リストの任意の行でスピナーを使用してコードを選択でき、毎回リスナーがトリガーされます。
EditText にフォーカスがある場合 (ポップアップ キーボードが表示されているかどうかに関係なく)、同じ行のスピナーが正常に機能し、リスナーがトリガーされます。ただし、リストの最後の行の場合、まったくトリガーできません。
最後の行の場合、別の行の EditText をクリックしてから、最後の行のスピナーを使用して選択しようとすると、リスナーがトリガーされます。これはすべての中で最も奇妙な部分です。
私は他の関連する問題に対して多くの解決策を試しましたが、今のところうまくいきません。これには、スピナーと EditText のフォーカス可能性をいじることが含まれます。スピナーに OnTouchListener を追加して、アイテム間で強制的にフォーカスを移動したり、意図的にフォーカスをクリアしたりします。これは私を夢中にさせているので、次に何を試すかについての助けや提案は大歓迎です。今のところ、これが将来何らかの形で修正できることを期待して、別の無関係な機能に移る必要があります.
行のxmlは次のとおりです
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/race_line"
android:textSize="16sp"
android:textStyle="bold"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingRight="10dip"
android:text="@string/race_line"
/>
<TextView
android:id="@+id/race_number"
android:textSize="16sp"
android:textStyle="bold"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingRight="10dip"
android:layout_toRightOf="@id/race_line"
/>
<EditText
android:id="@+id/result"
android:layout_width="100dip"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/race_number"
android:inputType="number"
android:imeOptions="actionDone"
android:imeActionLabel="Done"
android:focusableInTouchMode="true"
android:focusable="true"
/>
<Spinner
android:id="@+id/result_code_spinner"
android:layout_width="100dip"
android:layout_height="wrap_content"
android:prompt="@string/result_prompt"
android:layout_toRightOf="@id/result"
android:focusableInTouchMode="false"
android:focusable="true"
/>
</RelativeLayout>
そして、ここにコードがあります
public class ResultsEntryListAdapter extends BaseAdapter {
protected static ArrayList<resultObj> combinedList;
private Context mContext;
private LayoutInflater mInflater;
public ResultsEntryListAdapter(Context context, ArrayList<resultObj> listToDisplay) {
combinedList = listToDisplay;
mInflater = LayoutInflater.from(context);
mContext = context;
}
public int getCount() {
return combinedList.size();
}
public Object getItem(int position) {
return combinedList.get(position);
}
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
final int pos = position;
final ViewHolder holder;
// Add an on click listener to this method that will update the source data in the calling activity when items change
if (convertView == null) {
convertView = mInflater.inflate(R.layout.result_row, null);
holder = new ViewHolder();
holder.race_line = (TextView) convertView.findViewById(R.id.race_line);
holder.race_number = (TextView) convertView.findViewById(R.id.race_number);
holder.result = (EditText) convertView.findViewById(R.id.result);
holder.result_code_spinner = (Spinner) convertView.findViewById(R.id.result_code_spinner);
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(
mContext, R.array.result_codes, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
holder.result_code_spinner.setAdapter(adapter);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
/* If the user enters a result code using the spinner then put the result code into the
* data structure and set the numerical result (string) to a null value.
*/
final OnItemSelectedListener spinnerListener = new OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> av, View v, int spinPosition, long id) {
int spin_position = spinPosition;
// Stick the result of the selection back into the data bound to the view
// This stops the selection vanishing when the view is scrolled off the screen
combinedList.get(pos).setSpinPosition(spin_position);
int result = 0;
if (spin_position != 0) { result = 0;
if (spin_position == 11) {
// Special case of RDG with score:
// Do nothing with the result as we have to take it as entered
holder.result_code_spinner.setSelection(11);
} else if (spin_position == 15) {
// Another special case ZFP. Take score as entered here as well
holder.result_code_spinner.setSelection(15);
} else {
// put the encoded result into the data structure
combinedList.get(pos).setResult(Integer.toString(result));
holder.result.setText("");
}
}
}
@Override
public void onNothingSelected(AdapterView<?> arg0) {
// Do nothing, change nothing
}
};
/* The result value needs to be saved if one of several things happen:
* 1. The focus moves away from the cell being edited
* 2. The done/return key is pressed on the keyboard
* 3. The back button is pressed (to dismiss the keyboard)
*/
class DoneOnEditorActionListener implements OnEditorActionListener {
@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if (actionId == EditorInfo.IME_ACTION_DONE) {
InputMethodManager imm = (InputMethodManager)v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
EditText et = (EditText) v;
String sResult = et.getText().toString();
int result = sResult.equals("") ? 0 : Integer.parseInt(sResult);
if (result > 0 ) {
combinedList.get(pos).setResult(sResult);
} else if (result == 0) {
combinedList.get(pos).setResult("");
}
// Special case of RDG needs to retain the spin position if a result is then entered
if (combinedList.get(pos).getSpinPosition() != 11 && combinedList.get(pos).getSpinPosition() != 15) {
combinedList.get(pos).setSpinPosition(0);
}
holder.result_code_spinner.setSelection(0);
//holder.result.clearFocus(); //move focus away
return true;
}
return true;
}
}
final OnFocusChangeListener resultFocusListener = new OnFocusChangeListener() {
@Override
// Called when the user touches the editText to enter a score
public void onFocusChange(View v, boolean hasFocus) {
EditText et = (EditText) v;
if (hasFocus == false) {
String sResult = et.getText().toString();
int result = sResult.equals("") ? 0 : Integer.parseInt(sResult);
if (result > 0 ) {
combinedList.get(pos).setResult(sResult);
} else if (result == 0) {
combinedList.get(pos).setResult("");
}
int spinPosition = combinedList.get(pos).getSpinPosition();
if (spinPosition != 11 && spinPosition != 15) {
combinedList.get(pos).setSpinPosition(spinPosition);
holder.result_code_spinner.setSelection(spinPosition);
holder.result.clearFocus();
}
}
}
};
/* If the user enters a numerical result then check it is positive and put it into the
* data structure. At the same time set the spin position to 0 to indicate this is a
* valid result.
*/
holder.result_code_spinner.setOnItemSelectedListener(spinnerListener);
holder.result.setOnEditorActionListener(new DoneOnEditorActionListener());
holder.result.setOnFocusChangeListener(resultFocusListener);
// The race_line just says "Race:" for now but in future we may want to allow races to have names and fill in the name here
holder.race_line.setText(R.string.race_line);
holder.race_number.setText(combinedList.get(position).getRaceNumber());
String sResult = combinedList.get(position).getResult();
int spinPosition = combinedList.get(position).getSpinPosition();
if (sResult.equals("")) {
holder.result.setText("");
holder.result_code_spinner.setSelection(spinPosition); // spin position may be 0 or +ve, display it anyway
} else { // result is non-zero so need to display either the value or the spin position
int result = Integer.parseInt(sResult);
if (spinPosition == 11 || spinPosition == 15) {
// Display both spinner and result text
holder.result.setText(Integer.toString(result));
holder.result_code_spinner.setSelection(spinPosition);
} else if (result > 0) {
holder.result.setText(Integer.toString(result));
holder.result_code_spinner.setSelection(0);
} else {
holder.result.setText("");
holder.result_code_spinner.setSelection(combinedList.get(position).getSpinPosition());
}
}
return convertView;
}
static class ViewHolder {
TextView race_line;
TextView race_number;
EditText result;
Spinner result_code_spinner;
}
}