I've got a ListView with several rows. Every row consists of 7 TextViews which react to onClick() events.
This all works perfectly fine but when the user clicks on the margins of the row, where no TextView catches the onClick() event, the root view - a LinearLayout - get's highlighted.
This is normal behaviour of course but as nothing happens by clicking there I don't want the Linear Layout to be highlighted.
Is there any way of disabling this behaviour but keep catching the onClick() events on the TextViews?
(The onClick listener is set inside the adapters getView() method)
Here some extract of the xml file. As one can see I've tried some things but they don't work.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:longClickable="false"
android:clickable="false"
android:focusable="false"
android:focusableInTouchMode="false">
<TextView
android:id="#+id/listelement_weekoverview_tv_mo"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="1dp"
android:layout_weight="1"
android:background="#drawable/weeklylist_rndrectangle"
android:gravity="center_horizontal"
android:singleLine="false"
android:textColor="#color/appcolor_red_base" />
...
</LinearLayout>
unclicked version
clicked version
I've found a solution.
Simply overwrite the isEnabled (int position) method in your custom Adapter like this:
#Override
public boolean isEnabled (int position) {
return false;
}
Related
The whole thing looks like this:
+---------+---------+
| Mon | 10:00AM |
+---------+---------+
It's a LinearLayout with two TextViews. I want click events to go through 'Mon' part and change background of the LinearLayout on click. '10:00AM' still needs to accept separate click events.
The XML:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:orientation="horizontal"
android:background="#drawable/button_filled_white"
android:clickable="true"
>
<TextView android:text="MON"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:clickable="false"
android:enabled="false"
android:focusable="false"
/>
<TextView android:text="10:00AM"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:id="#+id/txtTime"
/>
</LinearLayout>
To let click events to go thorough 'MON' TextView, I tried setting clickable, focusable and enabled to false in a various combination but still, the background of LinearLayout doesn't change.
If I remove child TextViews, the LinearLayout is clickable and I can see the background changing its color when clicked:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:orientation="horizontal"
android:background="#drawable/button_filled_white"
android:clickable="true"
/>
I'm aware of ViewGroup.onInterceptTouchEvent() but I'm looking for a XML way since handling ViewGroup.onInterceptTouchEvent() requires situation specific and view id specific implementations.
you can try to set
android:focusable="false"
to your 'Mon' child view
Sorry to answer my own question, but to help people with same problem, I will give more details.
The root cause was NestedScrollView.
I actually composited the LinearLayout inside NestedScrollView and that prevented clickable & focusable = false to work correctly. Setting to true actually works as expected (changing background & etc). But setting to false works only half as expected - ignores click, but doesn't pass click events to parent.
So if anyone is having same problem, take a look at your parent(or parent's parent) container. If it's scrollable container, you will have more challenges.
I have a RelativeLayout inside of a ScrollView that contains a Button and some TextViews and EditTexts.
In my xml layout file, I am defining android:onClick but it always takes two clicks of the button to fire the event. The button always gets the focus on the first click and fires the onClick event on the second click. I have tried setting focusable and focusableInTouchMode both to false but the behavior doesn't change.
Here is my layout file:
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
tools:context=".DensityActivity" >
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<TextView
...
<TextView
...
<TextView
...
<EditText
...
<Button
android:id="#+id/ad_button_calculate"
android:layout_width="112dp"
android:layout_height="wrap_content"
android:layout_below="#id/ad_edit_obs_temp"
android:layout_alignParentRight="true"
android:layout_marginTop="20pt"
android:paddingLeft="6pt"
android:onClick="onClick"
android:focusable="false"
android:focusableInTouchMode="false"
android:text="#string/button_calculate" />
<TextView
...
</RelativeLayout>
</ScrollView>
Any ideas or suggestions as to why the focusable and focusableInTouchMode don't seem to do anything?
I thought it might be my onClick() method not doing what it should so I reduced it to something simple just to see and it behaves the same. Here is my simplified onClick():
public void onClick(View view) {
new AlertDialog.Builder(this).setTitle("Argh").setMessage("Watch out!").setNeutralButton("Close", null).show();
}
OK, I found it. It was, of course, my own mistake.
At the end of my onCreate method I was doing this:
// Set the focus to the calculate button so the keyboard won't show up automatically
Button calcButton = (Button)findViewById( R.id.ac_button_calculate );
calcButton.setFocusable( true );
calcButton.setFocusableInTouchMode( true );
calcButton.requestFocus();
So of course, no matter what I did in my xml file, I was overriding it in my code.
Instead, I used this to hide the keyboard:
getWindow().setSoftInputMode( WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN );
Which works great.
I have a ListView in my application which can, after user requests it, be re-arrangeable via the drag of an imageview at the start of each listview's row. I present the user with the listview in a small window, and in order to maximize the space, I set the visibility of the drag view as GONE, and plan on only setting it to Visible when user selects a menu item that calls for Edit List Items.
Here's the layout for a row item:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?android:attr/activatedBackgroundIndicator"
android:orientation="horizontal" >
<ImageView
android:id="#id/drag_handle"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_margin="8dp"
android:visibility="gone"
android:src="#drawable/ic_drag_dots_holo_dark" />
<View
android:layout_width="1dp"
android:layout_height="match_parent"
android:layout_marginBottom="16dp"
android:layout_marginTop="16dp"
android:background="?android:attr/dividerVertical" />
<TextView
android:id="#+id/drag_n_drop_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:maxLines="1"
android:minHeight="24dp"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="?android:attr/textColorPrimary" />
</LinearLayout>
Here's the code for the menu selection:
#Override
public boolean onContextItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_edit_playlist:
if (inEditMode) {
//If we are already showing the drag view, hide it.
inEditMode = false;
findViewById(R.id.drag_handle).setVisibility(View.GONE);
}
else {
//If the drag view is hidden, make it visible.
inEditMode = true;
findViewById(R.id.drag_handle).setVisibility(View.VISIBLE);
}
return true;
default:
return super.onContextItemSelected(item);
}
}
The problem with this code, is that when I call setVisibility() it only changes the visibility of the drag view on the firstmost item of the listview, and the dragview on all other rows remains hidden.
What would I do to make ALL dragViews on all rows visible in this case?
EDIT
Here's an image of how I want it to look after pressing edit, and here's an image of how it looks right now, with the code above.
Thanks!
The problem with this code, is that when I call setVisibility() it
only changes the visibility of the drag view on the firstmost item of
the listview, and the dragview on all other rows remains hidden.
That behavior it's normal as you're trying to change the visibility of a View from a row using findViewById(), method which will return the first occurrence of a View with that id from the layout. That first occurrence will be the situated in the first visible row of the list(anyway the findViewById method will not work, as you can probably see the views in the ListView's rows will all have the same ids).
What would I do to make ALL dragViews on all rows visible in this
case?
The proper way is to let the adapter of the ListView know in which state it's currently in(inEditMode) and show/hide the drag handle in the getView method based on that. Once you do this all you have to do in the onContextItemSelected is to update the inEditMode state variable and call notifyDataSetChanged() method on the adapter.
I am trying to create a ListView similar to the Gmail app, where each row has a CheckBox on the left to facilitate multiple selection and actions via the contextual action bar, while at the same time, allow clicking each row to transition to another activity.
Originally, before adding the CheckBox the rows would indicate their selection with a light blue background color from the Holo theme I'm using and call onListItemClick in my ListFragment when clicked and onItemLongClick in my OnItemLongClickListener when long clicked.
When I add the CheckBox to my layout .xml file for the row view, the background no longer changes color and I no longer receive click or long click events. If I add android:longClickable="true" to the top ViewGroup in my view .xml then I start getting long click events again. But android:clickable="true" does not get me click events. And neither allows the background blue selection indication to return. Only the CheckBox itself provides visual touch indication with a blue background when touched.
What do I need to do to get the normal visual selection indication as well as click events on the ListView rows with the CheckBox in the view?
Here's the relevant portion of my view .xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:longClickable="true"
android:orientation="horizontal" >
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical"
android:paddingBottom="5dp"
android:paddingRight="12dp"
android:paddingTop="5dp" >
...
</LinearLayout>
</LinearLayout>
I wrote a blog post on this subject awhile back that you may find helpful. The problem is, in fact, that adding focusable elements (like CheckBox or Button) disables the ability to click the overall list item and their focusability has to be disabled. You should not add any clickable flags to the main layout either.
While adding checkbox in CAB please make it focusable="false", this will solved the problem of only one time called onItemCheckedStateChanged.
I create a ListView from an ArrayAdapter. Each row of ListView have an ImageView and a TextView. Now I handle clicked event by using setOnItemClickListener
lv = getListView();
lv.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
CategoryInfo cat = (CategoryInfo) lv
.getItemAtPosition(position);
showGameByCategory(Long.valueOf(cat.getId()), cat.getName());
}
});
When I click on a row, it will start another activity. On that activity, I have a button to go back to the ListView. When click that button, I'll call Activity.finish();.
Here's the problem: first time I open ListView and click on any items, it works fine and open new activity. But when I click button back and go back to ListView, I can't click to any items. My app have many tabs, if I switch to another tab and switch back to the ListView, I can click ListView item again. But anytime I click button back, the items are unclickable.
I test on 2 different OS and it works normally on Android 2.3 but this error occurred on Android 4.0.
Does anyone know how to fix this?
EDIT: this is my layout file:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="?android:attr/listPreferredItemHeight"
android:background="#drawable/listitem_selector_odd"
android:padding="6dip" >
<RelativeLayout
android:layout_width="0dip"
android:layout_height="fill_parent"
android:layout_weight="1"
android:orientation="vertical" >
<ImageView
android:id="#+id/avatar"
android:layout_width="70dp"
android:layout_height="70dp"
android:layout_marginRight="6dip"
android:layout_alignParentLeft="true"/>
<TextView
android:id="#+id/toptext"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_toRightOf="#+id/avatar"
android:layout_marginRight="6dip"
android:layout_weight="1"
android:gravity="center_vertical"
android:textColor="#000000"
android:textSize="18dp"
android:textStyle="bold" >
</TextView>
<ImageView
android:id="#+id/arrow"
android:layout_width="10dip"
android:layout_height="15dip"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginLeft="6dip"
android:layout_weight="1"
android:gravity="center_vertical"
android:src="#drawable/arrow_icon" />
</RelativeLayout>
</LinearLayout>
I had exactly the same problem as you. Even stranger, it happened on some tablet 4.0 or 4.1, while it didn't happen on a phone 4.1.
Using "descendentFocusabilty=blocksDescendants" didn't solve it.
Following the idea of user1603602, I ask for the invalidation of Views of the list (hence a redraw of elements of the list) each time the View becomes visible:
#Override
protected void onWindowVisibilityChanged(int visibility) {
super.onWindowVisibilityChanged(visibility);
if (visibility == View.VISIBLE) {
list.invalidateViews();
}
}
As it reloads each items of the list, it can be annoying if you load images with animations for example, but it solves the problem, and it keep the scrolled position.
I had the same problem and just figured out a way to solve it. Remove the listview, then add it back. This will force the view to refresh to the original working state.
for example if your ListView lv is on a LinearLayout lout
lout.removeView(lv);
lout.addView(lv);
make sure you call this from the UI thread.
I think this is the same issue as described here
I used a custom adapter containing an array of Views. Within getView(position, ...), I return the View at the specified position. Apparently, ListView didn't like this and sometimes (platform specific) recycles views that shouldn't be recycled.