-4

I am trying to create a ListView with editable lines:

MainActivity

public class AlertDialogList extends AppCompatActivity {
protected final String DEBUG_TAG = this.getClass().getName();
List<Pair<String, String>> headers = new LinkedList<>();

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    headers.add(new Pair<String, String>("Event", "?"));
    headers.add(new Pair<String, String>("Site", "?"));
    headers.add(new Pair<String, String>("Date", "?"));
    headers.add(new Pair<String, String>("Round", "?"));
    headers.add(new Pair<String, String>("White", "?"));
    headers.add(new Pair<String, String>("Black", "?"));
    headers.add(new Pair<String, String>("Result", "?"));
    headers.add(new Pair<String, String>("WhiteElo", "?"));
    headers.add(new Pair<String, String>("BlackElo", "?"));
    headers.add(new Pair<String, String>("ECO", "?"));

    RelativeLayout layout = new RelativeLayout(this);
    RelativeLayout.LayoutParams rlp = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT);
    layout.setBackgroundColor(Color.GREEN);
    this.setContentView(layout, rlp);

    Button button = new Button(this);
    button.setText("Show Alert Dialog");
    button.setLayoutParams(new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
    layout.addView(button);

    button.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            launchDialog();
        }
    });
}

public void launchDialog() {
    final AlertDialog.Builder builder = new AlertDialog.Builder(AlertDialogList.this);
    ArrayAdapter arrayAdapter = new CPHeaderListAdapter(this, headers);
    builder.setSingleChoiceItems(arrayAdapter, -1, null);

    builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialogInterface, int i) {
            Log.d(DEBUG_TAG, "PositiveButton onClick()");
        }
    });

    AlertDialog dialog = builder.create();
    dialog.show();
}
}

Custom ArrayAdapter

public class CPHeaderListAdapter extends ArrayAdapter<Object> {
protected final String DEBUG_TAG = this.getClass().getName();
private List<Pair<String, String>> headerList;
private LayoutInflater layoutInflater;

public CPHeaderListAdapter(Context context, @NonNull List<Pair<String, String>> headers) {
    super(context, R.layout.list_view, R.id.headerValue);
    headerList = headers;
    layoutInflater = LayoutInflater.from(context.getApplicationContext());
}

@Override
public int getCount() {
    return headerList.size();
}

@Override
public Object getItem(int position) {
    return headerList.get(position);
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    RowViewHolder rowViewHolder;
    if (convertView == null) {
        convertView = layoutInflater.inflate(R.layout.list_view, null);
        rowViewHolder = new RowViewHolder();
        convertView.setTag(rowViewHolder);
        LinearLayout layout = convertView.findViewById(R.id.headerRowLayout);
        layout.setVisibility(View.VISIBLE);
        rowViewHolder.labelView = convertView.findViewById(R.id.headerLabel);
        rowViewHolder.valueView = convertView.findViewById(R.id.headerValue);
        rowViewHolder.actionButton = convertView.findViewById(R.id.headerActionButton);
    } else {
        rowViewHolder = (RowViewHolder) convertView.getTag();
    }

    parent.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);

    rowViewHolder.valueView.setTag(position);
    rowViewHolder.actionButton.setTag(position);
    Pair<String, String> header = headerList.get(position);
    rowViewHolder.labelView.setText(header.first);
    rowViewHolder.valueView.setText(header.second);
    rowViewHolder.valueView.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            return false;
        }
    });

    rowViewHolder.actionButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            int position = Integer.valueOf(v.getTag().toString());
            Log.d(DEBUG_TAG, String.format("onClick actionButton %s, #%d", v.getTag().toString(), position));
        }
    });

    rowViewHolder.valueView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
        @Override
        public void onFocusChange(View v, boolean hasFocus) {
            if (!hasFocus) {
                int position = Integer.valueOf(v.getTag().toString());
                Pair<String, String> header = headerList.get(position);
                String label = header.first;
                String text = ((TextView) v).getText().toString();
                Pair<String, String> newHeader = new Pair<>(label, text);
                headerList.set(position, newHeader);
            }
        }
    });
    return convertView;
}

private class RowViewHolder {
    TextView labelView;
    TextView valueView;
    Button actionButton;
}
}

layout

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
>

<LinearLayout
    android:id="@+id/headerRowLayout"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:layout_marginLeft="10sp"
    android:layout_marginRight="10sp"
    >

    <TextView
        android:id="@+id/headerLabel"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:textColor="#505050"
        />

    <EditText
        android:id="@+id/headerValue"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:inputType="text"
        android:scrollHorizontally="true"
        android:textColor="#000000"
        />

    <Button android:id="@+id/headerActionButton"
        android:text="del"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        />

</LinearLayout>


It has a major defect - when I click on a field that shows '?', Android does not pop up the keyboard:
enter image description here

Trying to solve this, I added an invisible EditText, just before

 AlertDialog dialog = builder.create();

line:

    EditText editText = new EditText(AlertDialogList.this.getApplicationContext());
editText.setVisibility(View.GONE);
builder.setView(editText);


Now all lines work as expected:
enter image description here
but the button 'OK' at the bottom disappeared (if the screen is small enough):
enter image description here
Interesting that it used to work with AndroidStudio 2 and older SDK (21?).
Can anyone tell how to make it work correctly?

Azat Ibrakov
  • 9,998
  • 9
  • 38
  • 50
Alex B
  • 347
  • 1
  • 3
  • 9
  • 2
    Please don't just link to your project off-site. You need to include a [mcve] in the question itself. – Mike M. Oct 20 '18 at 05:54
  • The link is updated, all generated files are removed. – Alex B Oct 20 '18 at 16:53
  • 1
    No, I mean that the minimal code, XML, etc., needed to demonstrate your issue should be in the question, as text. Please don't link off-site to necessary material. – Mike M. Oct 21 '18 at 17:35

1 Answers1

0

You can use this code to create AlertDialog with whatever you want. Place your ListView on layout/your_layout_xml and access them programmatically from dialogView and use as usual.

    AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(getActivity());

    LayoutInflater inflater = getActivity().getLayoutInflater();
    final View dialogView = inflater.inflate(R.layout.your_layout_xml, null);
    dialogBuilder.setView(dialogView);

    final ListView listView= dialogView.findViewById(R.id.listView); 

    dialogBuilder.setTitle(getString(R.string.app_name));
    dialogBuilder.setIcon(R.mipmap.ic_launcher);
    dialogBuilder.setCancelable(true);

    dialogBuilder.setMessage(getString(R.string.app_dialog_title));


    dialogBuilder.setPositiveButton(getString(R.string.dialog_ok), new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int whichButton) { 
            //your code 
        }
    });


    dialogBuilder.setNeutralButton(R.string.dialog_cancel, new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int whichButton) {
            dialog.dismiss(); 
        }
    });

    AlertDialog b = dialogBuilder.create();
    b.show();
  • Apparently you missed the point. I do create positive button in the dialog, exactly the way you suggest. The problem is that because of the invisible EditText (to make soft keyboard to pop up when user clicks on a row) this button does not show up on the screen, ListView occupies the whole real estate. – Alex B Oct 20 '18 at 16:58
  • This question has been asked already - https://stackoverflow.com/questions/36872319/android-editable-listview-preference-dialog but there was not answered. – Alex B Oct 20 '18 at 17:02
  • you can use fixed-sized listview, maybe it helps – Shamxal Bayramov Oct 23 '18 at 11:10