2
votes

I made an InfoscreenActivity which brings up an "Settings/About" page in my app (with app version info, licenses, contact, setup and back-up options). The items on that page are generated in a ListView using a custom ArrayAdapter called InfoscreenAdapter.

Here are the relevant classes and xml layout files.

The Activity InfoscreenActivity:

public class InfoscreenActivity extends ActionBarActivity {
    private static final String TAG = "InfoscreenActivity";
    private InfoscreenItem appVersion;
    private InfoscreenItem iiLicenses;
    private InfoscreenItem contactUs = new InfoscreenItem("Contact us");
    private InfoscreenItem iiSetup = new InfoscreenItem("Launch Setup");
    private InfoscreenItem iiBackup = new InfoscreenItem("Perform Backup");

    ListView lv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        if(AppConfig.DEBUG) Log.i(TAG, "launching onCreate() ...");

        String appVersionString;

        if(AppConfig.DEBUG) Log.i(TAG, "trying to fetch the version name ...");
        try {
            appVersionString = SetupActivity.getVersionName(this);
            appVersion = new InfoscreenItem("App version", appVersionString);
        } catch (Exception e) {
            if(AppConfig.DEBUG) Log.e(TAG, e.getMessage());
        }

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_infoscreen);

        iiLicenses = new InfoscreenItem(getResources().getString(R.string.title_activity_licenses));

        // Get ListView object from xml
        lv = (ListView) findViewById(R.id.infoscreenListViewID);
        // Defined Array values to show in ListView
        InfoscreenItem[] items = new InfoscreenItem[] {appVersion, contactUs, iiLicenses, iiSetup, iiBackup};
        // Define a new InfoscreenAdapter
        InfoscreenAdapter adapter = new InfoscreenAdapter(this, items);
        // Assign adapter to ListView
        if(AppConfig.DEBUG) Log.i(TAG, "setting adapter");
        lv.setAdapter(adapter);

        // React to user clicks on item
        lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {

            public void onItemClick(AdapterView<?> parentAdapter, View view, int position,
                                    long id) {
                if(AppConfig.DEBUG) Log.i(TAG, "item " + Integer.toString(position) + " clicked.");

                // for the "Contact us" item
                if(position == 1) {
                    TextView clickedView = (TextView) view.findViewById(R.id.textView);
                    onContactClick(clickedView);
                }

                // for the "Licenses" item
                if(position == 2) {
                    TextView clickedView = (TextView) view.findViewById(R.id.textView);
                    onLicensesClick(clickedView);
                }

                // for the "Setup" item
                if (position == 3) {
                    if (AppConfig.DEBUG) Log.d(TAG, "launching Setup Activity...");
                    startActivity(new Intent(getApplication(), SetupActivity.class));
                }

                // for the "Backup" item
                if (position == 4) {
                    Intent iBackup = new Intent(getApplication(), BackupAndRestoreActivity.class);
                    iBackup.putExtra("MODE", 1);
                    startActivity(iBackup);
                }

            }
        });

        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        if(AppConfig.DEBUG) Log.i(TAG, "exiting onCreate() ...");
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        if(AppConfig.DEBUG) Log.i(TAG, "onCreateOptionsMenu() ...");
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_infoscreen, menu);
        if(AppConfig.DEBUG) Log.i(TAG, "exiting onCreateOptionsMenu() ...");
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        else if (id == android.R.id.home) {
            finish();
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    public void onContactClick(View v) {
        Intent email = new Intent(Intent.ACTION_SEND);
        email.putExtra(Intent.EXTRA_EMAIL, new String[]{"[email protected]"});
        email.putExtra(Intent.EXTRA_SUBJECT, "(subject)");
        email.putExtra(Intent.EXTRA_TEXT, "(message)");
        email.setType("message/rfc822");
        startActivity(Intent.createChooser(email, "Choose an Email client :"));
    }

    public void onLicensesClick(View v) {
        if(AppConfig.DEBUG) Log.i(TAG, "onLicensesClick() ...");

        startActivity(new Intent(InfoscreenActivity.this, LicensesActivity.class));
    }
}

The Adapter InfoscreenAdapter:

public class InfoscreenAdapter extends ArrayAdapter<InfoscreenItem> {
    private static final String TAG = "InfoscreenAdapter";
    private Context context;
    private InfoscreenItem[] infoscreenItems;

    // constructor
    public InfoscreenAdapter(Context context, InfoscreenItem[] infoscreenItems) {
        super(context, -1, infoscreenItems);
        if(AppConfig.DEBUG) Log.i(TAG, "entering InfoscreenAdapter constructor");
        this.context = context;
        this.infoscreenItems = infoscreenItems;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        if(AppConfig.DEBUG) Log.i(TAG, "fetching View " + Integer.toString(position) +
                ". Title: " + infoscreenItems[position].getItemTitle() + ", name: " +  infoscreenItems[position].getItemName());

        // the infoscreenItem has only 1 line (title)
        if(infoscreenItems[position].getItemName().equals("")) {
            // inflate the Layout from the infoscreen_single_line.xml
            LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = inflater.inflate(R.layout.item_infoscreen_single_line, parent, false);
            // get the TextView from the layout
            TextView tv = (TextView) convertView.findViewById(R.id.textView);
            //set its text
            tv.setText(infoscreenItems[position].getItemTitle());

            return convertView;
        }

        // the infoscreenItem has 2 lines (title & name)
        else {
            // inflate the Layout from the infoscreen_dual_line xml
            LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = inflater.inflate(R.layout.item_infoscreen_dual_line, parent, false);

            // get the TextView for the title
            TextView appVersionTextView = (TextView) convertView.findViewById(R.id.textView_title);
            //set its text
            appVersionTextView.setText(infoscreenItems[position].getItemTitle());
            // get the TextView for the version name
            TextView appVersionNameTextView = (TextView) convertView.findViewById(R.id.textView_versionName);
            //set its text
            appVersionNameTextView.setText(infoscreenItems[position].getItemName());

            return convertView;
        }
    }
}

The class InfoscreenItem:

public class InfoscreenItem {
    private String itemTitle;
    private String itemName;

    // constructors
    public InfoscreenItem () {
        itemTitle = "";
        itemName = "";
    }

    public InfoscreenItem (String iTitle){
        itemTitle = iTitle;
        itemName = "";
    }

    public InfoscreenItem (String iTitle, String iName){
        itemTitle = iTitle;
        itemName = iName;
    }

    public String getItemTitle() {
        return itemTitle;
    }

    public String getItemName() {
        return itemName;
    }
}

The xml files used for the formatting.

activity_infoscreen.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="at.dimi3.crew2go.InfoscreenActivity"
    tools:ignore="MergeRootFrame"
    android:orientation="vertical">

    <ListView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/infoscreenListViewID"
        android:clickable="true" />

</LinearLayout>

item_infoscreen_single_line.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:text="Medium Text"
        android:id="@+id/textView"
        android:paddingLeft="20dp"
        android:paddingTop="10dp"
        android:paddingRight="20dp"
        android:paddingBottom="10dp"
        android:clickable="true" />
</LinearLayout>

item_infoscreen_dual_line.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:text="Medium Text"
        android:id="@+id/textView_title"
        android:paddingLeft="20dp"
        android:paddingTop="10dp"
        android:paddingRight="20dp"
        android:paddingBottom="5dp"
        android:clickable="true" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceSmall"
        android:text="Small Text"
        android:id="@+id/textView_versionName"
        android:paddingLeft="20dp"
        android:paddingRight="20dp"
        android:paddingBottom="10dp"
        android:clickable="true" />
</LinearLayout>

Now all is working as intended, except for the fact that in the ListView of the "Infoscreen", the items are only clickable NEXT to the text. Is there any way to make the entire ListView item reacting to the click, regardless where you click on the item? Am I missing something in the xml layout templates? I've tried setting android:clickable="true", removing it, played around changing the android:layout_width="wrap_content" to match_parent or fill_parent (as suggested in other similar threads - those were not clickable at all though, so not entirely the same problem as I'm having).

3

3 Answers

1
votes

In your item_infoscreen_dual_line.xml or item_infoscreen_single_line.xml (I don't know which one causes your trouble) give an id to your linearLayout. Now find that layout and set the OnClickListener on that layout.

0
votes

Simple. You have given padding to your textview. But you want to click the entire LinearLayout item. For that instead of writing padding to TextView , give it for LinearLayout

0
votes

Ok, thanks a lot for the inputs. Doing a bit more googling I've stumbled upon the following example and created this exact project in my Android Studio. Clicking works everywhere in this example so I started removing xml attributes one by one to match the xml in the example and it turns out that removing android:clickable="true" solves the problem. I'm a bit confused (it sounds contradictory to me) but it works.