2

ListView からユーザー入力を表示および取得するためのカスタム アダプターがあります。リストの行には、TextView、EditText、および Spinner が含まれています。困っているのはスピナーです。このアプリケーションは、競技者の結果がフィニッシュ位置 (EditText に入力) または結果コード (所定の値のセットからスピナーを使用して選択) のいずれかである、セーリング レースの採点に関するものです。私と同じような問題を抱えている人はたくさんいるようですが、ここにいるような人はいません。

問題は、OnItemSelectedListener が特定の状況でのみトリガーされ、トリガーする必要があるたびにトリガーされるわけではなく、対応する EditText にフォーカスがあるかどうか、または別の行の EditText にフォーカスがあるかどうかによって状況が異なることです。

  1. リストが最初に表示されたとき、フォーカスは何も表示されず、リストの任意の行でスピナーを使用してコードを選択でき、毎回リスナーがトリガーされます。

  2. EditText にフォーカスがある場合 (ポップアップ キーボードが表示されているかどうかに関係なく)、同じ行のスピナーが正常に機能し、リスナーがトリガーされます。ただし、リストの最後の行の場合、まったくトリガーできません。

  3. 最後の行の場合、別の行の 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;

}
}
4

0 に答える 0