List item with button not clickable anymore - android

I have a list item with a button inside.
When the button is shown, the list item is not clickable anymore.
To make it clickable again, I have replaced the button with a view. The problem is that, when the list item is clicked, the button changes background image (like if it is clicked). How can avoid this bad behaviour?
Thanks

Set the following properties for you button
android:focusable="false"
android:focusableInTouchMode="false"
For ImageButton, also add the following to the parent view
android:descendantFocusability="blocksDescendants"

Actually I have just found a wonderful explaination: http://android.cyrilmottier.com/?p=525
The problem and the solution is very well explained there.

The part of the link provided by #Matroska that answers the question:
You must add
android:descendantFocusability="blocksDescendants"
to the parent ViewGroup that defines the layout of an item of your ListView.
Note: this will no longer allow you to focus on the inner button with hardware buttons.
(sorry, I cannot comment yet)

You can try this:
yourButton.setFocusable(false);
yourButton.setFocusableInTouchMode(false);

Here is an example of a clickable button inside a ListView. If you want to download the project you can download the IntelliJ Gradle project from my web site:
http://developersfound.com/ListButtonClickExample.zip
The custom adapter in this example has the click listener instead of the listener being inside the Fragment or Activity. It's done is such a way that there is only on listener object and all button are bound to them for efficiency.
Here is the ListItem layout:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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"
tools:context="com.jc_systems.listbuttonclickexample.app.ItemFragment">
<LinearLayout
android:id="#+id/test_container"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<ImageView
android:id="#+id/image_list_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/exaple_icon"
android:layout_weight=".1"
android:layout_gravity="left|top"/>
<TextView
android:id="#+id/lbl_list_item"
android:layout_width="168dp"
android:layout_height="wrap_content"
android:text="I think this should take up two lines..."
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:gravity="center_vertical|center_horizontal"
android:layout_gravity="center_vertical"/>
<Button
android:id="#+id/cmd_list_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello"
android:layout_weight="0.2"
android:paddingLeft="0dp"
android:paddingRight="0dp"
android:paddingTop="0dp"
android:paddingBottom="0dp"
android:layout_gravity="right|top"/>
</LinearLayout>
</FrameLayout>
And here is the CustomAdapter:
import android.app.Activity;
import android.app.AlertDialog;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.ArrayList;
public class MyCustomAdapter extends ArrayAdapter {
private final ArrayList<FragmentItems> list;
private static Activity context;
private View.OnClickListener adaptrDynaListener = null;
public MyCustomAdapter(Activity context, ArrayList<FragmentItems> list) {
super(context, R.layout.fragment_items, list);
this.context = context;
this.list = list;
adaptrDynaListener = new View.OnClickListener() {
#Override
public void onClick(View v) {
String buttonText = ((Button) v).getText().toString();
new AlertDialog.Builder(MyCustomAdapter.context).setTitle("Alert").setMessage(buttonText).setNeutralButton("OK", null).show();
}
};
}
static class ViewHolder {
protected ImageView image_list_image;
protected TextView lbl_list_item;
protected Button cmd_list_button;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = null;
ViewHolder viewHolder = new ViewHolder();
if (convertView == null) {
LayoutInflater inflator = context.getLayoutInflater();
view = inflator.inflate(R.layout.fragment_items, null);
viewHolder.image_list_image = (ImageView) view.findViewById(R.id.image_list_image);
viewHolder.lbl_list_item = (TextView) view.findViewById(R.id.lbl_list_item);
viewHolder.cmd_list_button = (Button) view.findViewById(R.id.cmd_list_button);
viewHolder.cmd_list_button.setTag(viewHolder);
view.setTag(viewHolder);
}
else {
view = convertView;
viewHolder = (ViewHolder) view.getTag();
}
ViewHolder holder = (ViewHolder) view.getTag();
holder.lbl_list_item.setText(list.get(position).getMessage());
holder.cmd_list_button.setText(list.get(position).getButtonText());
holder.cmd_list_button.setOnClickListener(adaptrDynaListener);
return view;
}//public View getView(int position, View convertView, ViewGroup parent)
public int getCount() {
if(list.size() <= 0) {
return 1;
}
return list.size();
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
}
I've tested this Adapter pattern quite extensively and it seems very stable in ListView, ListActivities and ListFragments.

You can create an xml file that contains the clicked behavior of the view. Create an xml file, custom_button.xml (or whatever you want to call it) and fill it with this code:
<?xml version="1.0" encoding="UTF-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Focused -->
<item android:state_focused="true" android:state_pressed="false" android:color="#color/black"/>
<!-- Pressed -->
<item android:state_focused="false" android:state_pressed="true" android:color="#color/black"/>
<!-- Focused+Pressed -->
<item android:state_focused="true" android:state_pressed="true" android:color="#color/black"/>
<!-- Disabled -->
<item android:state_enabled="false" android:color="#color/dark_grey_text"/>
<!-- Default -->
<item android:color="#color/white"/>
</selector>
You can then change the
android:color=""
To
android:drawable=""
And assign them to any drawable resources you have in your drawable folder. Then in the xml file for your layout containing the view, add:
android:background="custom_button"

Related

Android ListView :: Scrolling ListView while item is selected causes display problems

Alright, so I'm using a ListView with a custom adapter. Everything works fine and dandy...until the user selects a ListView row and tries to scroll.
When the user selects a row, the background color of that row changes to blue (which is good).
But, problems occur when we begin scrolling: When we scroll past the selected row, the blue fixes itself to either the bottom or the top of the ListView, depending on which way we were scrolling.
Selected row changes color on touch (good)
Part of the background of selected row is fixed to top when scrolling down (not good)
Part of the background of selected row is fixed to bottom when scrolling up (not good)
Here is my source code:
List View that I'm populating dynamically
<ListView
android:id="#+id/tallyDataListView"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:divider="#000000"
android:dividerHeight="1dp"
android:fadeScrollbars="false"
android:listSelector="#0099FF" >
layout_list_view_row.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<View
android:focusable="false"
android:focusableInTouchMode="false"
style="#style/tableSideBorderLine" />
<TextView
android:id="#+id/COLUMN_PIPE_NUMBER"
android:layout_height="wrap_content"
android:layout_width="0dp"
android:layout_weight="1"
style="#style/tableColumn"
xmlns:android="http://schemas.android.com/apk/res/android" />
<View
android:focusable="false"
android:focusableInTouchMode="false"
style="#style/tableColumnDivider" />
<TextView
android:id="#+id/COLUMN_TOTAL_LENGTH"
android:layout_height="wrap_content"
android:layout_width="0dp"
android:layout_weight="1"
style="#style/tableColumn"
xmlns:android="http://schemas.android.com/apk/res/android" />
<View
android:focusable="false"
android:focusableInTouchMode="false"
style="#style/tableColumnDivider" />
<TextView
android:id="#+id/COLUMN_ADJUSTED"
android:layout_height="wrap_content"
android:layout_width="0dp"
android:layout_weight="1"
style="#style/tableColumn"
xmlns:android="http://schemas.android.com/apk/res/android" />
<View
android:focusable="false"
android:focusableInTouchMode="false"
style="#style/tableSideBorderLine" />
</LinearLayout>
My Custom Adapter
import android.app.Activity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;
import java.util.ArrayList;
public class ListViewAdapter extends ArrayAdapter<String>{
LayoutInflater inflater;
private final ArrayList<String> adjustedValues;
private final ArrayList<String> pipeNumbers;
private final ArrayList<String> totalLengthValues;
public ListViewAdapter(Activity pContext, ArrayList<String> pPipeNumbers,
ArrayList<String> pTotalLengthValues, ArrayList<String> pAdjustedValues)
{
super(pContext, R.layout.layout_list_view_row, pAdjustedValues);
adjustedValues = pAdjustedValues;
pipeNumbers = pPipeNumbers;
totalLengthValues = pTotalLengthValues;
inflater = pContext.getLayoutInflater();
}
#Override
public View getView(int pPosition, View pView, ViewGroup pParent)
{
View view = inflater.inflate(R.layout.layout_list_view_row, pParent, false);
TextView col1 = (TextView)view.findViewById(R.id.COLUMN_PIPE_NUMBER);
col1.setText(pipeNumbers.get(pPosition));
TextView col2 = (TextView)view.findViewById(R.id.COLUMN_TOTAL_LENGTH);
col2.setText(totalLengthValues.get(pPosition));
TextView col3 = (TextView)view.findViewById(R.id.COLUMN_ADJUSTED);
col3.setText(adjustedValues.get(pPosition));
return view;
}
}
This is the common problem about the listview. When you scroll down it creates the new view every time. That is why the selected element from the top gets out of the focus and another element is selected.
For this problem you have to extend the BaseAdapter class and
#Override
public View getView(int position, View convertView, ViewGroup parent) {
Vehical vehical = vehicals.get(position);
ViewHolder viewHolder = null;
if(convertView==null)
{
viewHolder = new ViewHolder();
convertViewactivity.getLayoutInflater().inflate(R.layout.list_item,null);
convertView.setTag(viewHolder);
}
else
{
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.tvVehicalName = (TextView) convertView.findViewById(R.id.vehicle_name);
viewHolder.tvVehicalName.setText(vehical.getVehicalName());
if(vehical.isSelected()){
viewHolder.tvVehicalName.setTextColor(Color.RED);
}
else
{
viewHolder.tvVehicalName.setTextColor(Color.BLACK);
}
return convertView;
}
//On listener of the listview
searchList.setOnItemClickListener(
new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View view, int position, long arg3) {
if(searchAdapter.isItemSelected(position))
{
searchAdapter.setSelectedItem(position,false);
selectedList.remove(((Vehical)searchAdapter.getItem(position)).getVehicalName());
}
else
{
if(selectedList.size()<new_vehiclelimit){
searchAdapter.setSelectedItem(position,true);
selectedList.add(((Vehical)searchAdapter.getItem(position)).getVehicalName());
}
else
{
Toast.makeText(getApplicationContext(), "Vechicle Limit is Over", Toast.LENGTH_SHORT).show();
}
}
Keep a reference for selected row position in your Adapter, say
int selectedPos = -1;
The value will be -1 when no row is selected. And in the OnItemClickListener of the listview,update selectedPos with the clicked position and call notifyDatasetChanged() on the adapter. In the getView method of the adapter, check for the selectedPos value and highlight the row accordingly.

Android ListView listSelector not working

I am trying to set a custom selector to a ListView. It's working fine on newer devices but not working on lower version of devices.I want the ListView selected item to be stay highlighted.
Please help.
Thanks in advance.
ListView.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="match_parent"
android:orientation="vertical" >
<ListView
android:id="#+id/listViewBell"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:cacheColorHint="#00000000"
android:choiceMode="singleChoice"
android:divider="#b5b5b5"
android:dividerHeight="1dp"
android:listSelector="#drawable/list_selector_color" >
</ListView>
</LinearLayout>
list_selectror_color.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<solid android:color="#color/list_selector" />
<stroke
android:dashWidth="2dp"
android:width="1dp"
android:color="#color/white" />
</shape>
I have also tried with selector but nothing happens
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#drawable/list_selector_color" android:state_pressed="true"/>
<item android:drawable="#drawable/list_selector_color" android:state_focused="true"/>
<item android:drawable="#drawable/list_selector_color" android:state_selected="true"/>
<item android:drawable="#drawable/list_selector_normal"/>
</selector>
Here is my Custom adapter getView Method
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) mContext
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.listview_bell_items, parent,
false);
ImageView imageview = (ImageView) convertView
.findViewById(R.id.list_bell_image);
imageview.setImageResource(mDataImage[position]);
TextView textview = (TextView) convertView
.findViewById(R.id.txt_bell_title);
textview.setText(mDataText[position]);
return convertView;
}
I had similar problem. Sorry, cannot comment, so I post a possible answer.
Remove android:listSelector="#drawable/list_selector_color" property from your ListView declaration
In your R.layout.listview_bell_items specify your custom selector for a root layout. E.g., if root layout of your list item is RelativeLayout, try:
<RelativeLayout ... android:background="#drawable/listitem_selector">...
The same goes for any other type of Layout.
If this still still does not give you the result you want, provide more details.
Update
Ok, if nothing else helps, there's a temporary dirty workaround of your problem. I do not see why it would not work.
Introduce a selectedPos variable holding currently selected item.
private class MyAdapter extends .../*your base adapter*/ {
private static final int NOT_SELECTED = -1;
private int selectedPos = NOT_SELECTED;
// if called with the same position multiple lines it works as toggle
public void setSelection(int position) {
if (selectedPos == position) {
selectedPos = NOT_SELECTED;
} else {
selectedPos = position;
}
notifyDataSetChanged();
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = super.getView(position, convertView, parent);
if (position == selectedPos) {
// your color for selected item
view.setBackgroundColor(Color.parseColor("#000000"));
} else {
// your color for non-selected item
view.setBackgroundColor(Color.parseColor("#FFFFFF"));
}
return view;
}
}
Now, add the following code after you create and set ListView's adapter:
final MyAdapter adapter = new MyAdapter(...);
listView.setAdapter(adapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
adapter.setSelection(position);
}
});
That is what I found out:
To get the list selector working the are two approaches:
1)
You use the OnItemClickListener.
Then the list selector drawable/color will work as expected when set it on the list view.
Then you may use a TouchListener for getting ClickEvents of any child view instead of using a ClickListener.
2)
You have set ClickListener on any child of the row view.
In this case the list selector will not work when been set on the list view, so you have to set your list selector drawable/color as background of the row view.

Selectable TextView in a ListView (Animation missing)

I built a ListView with a Custom Adapter so that I have a Checkbox (invisible at the time) and a TextView to display some text.
Now I want to have the beautiful animation when selecting an item in the List (Background beeing blue for the time you touch the element). Is this possible?
I already added an OnLongTouchListener and it worked but no animation!
Would be cool to get some help :)
Layout-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="match_parent"
android:orientation="horizontal" >
<CheckBox
android:id="#+id/list_checkbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="false"
android:visibility="gone"
android:text=""
android:focusable="false"
android:clickable="false">
</CheckBox>
<TextView
android:id="#+id/list_text"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text=""
android:clickable="true"
android:longClickable="true" >
</TextView>
</LinearLayout>
The Java-Code:
private class CommunityListAdapter extends ArrayAdapter<Community> {
private List<Community> items;
private Context context;
public CommunityListAdapter(Context context, List<Community> communities) {
super(context, R.layout.list_item, communities);
this.items = communities;
this.context = context;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
if (view == null) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.list_item, null);
}
Community item = items.get(position);
if(item != null) {
TextView textView = (TextView) view.findViewById(R.id.list_text);
if(textView != null) {
textView.setText(item.getName());
textView.setOnLongClickListener(new OnLongClickListener() {
public boolean onLongClick(View view) {
startActionMode(new MultiChoiseCABListener());
Toast.makeText(context, "TEST", 10).show();
return false;
}
});
}
}
return view;
}
}
Create pressed state xml in your drawables in which you set different bitmaps to be displayed at different states of tap, and set that xml as your main layout background.
example state xml.
list_item_bg_state.xml
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" android:drawable="#drawable/blue_bg" />
<item android:drawable="#drawable/white_bg"/>
</selector>
where blue_bg and white_bg are two.png images in your drawables.
note above xml should be in your drawables folder. Now set this xml as background of your list item main layout. like,
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/list_item_bg_state"
android:orientation="horizontal" >
</LinearLayout>
regards,
Aqif
You havent defined animation please define animation and associate with this view.
Animation a = new AlphaAnimation(1.00f, 0.00f);
a.setDuration(1000);
YOURTEXTVIEW.startAnimation(a);

Android displaying text when ListView is empty

I'm setting a TextView with the id #android:id/empty to display a message when there are no items in the ListView. However, this TextView gets displayed even if there are items in the ListView, right before the items show up.
How can I make it such that it only gets displayed when there are no elements in the ListView?
<?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="match_parent"
android:orientation="vertical" >
<ListView
android:id="#android:id/list"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:dividerHeight="1dp" >
</ListView>
<TextView
android:id="#android:id/empty"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/empty_list" />
</LinearLayout>
PS: I'm using a Loader and a SimpleCursorAdapter with a ListFragment.
I'm guessing you are using a regular Fragment or Activity with a ListView inside of it. If you are, you must add the empty layout to the ListView manually.
E.g.
ListView lv = (ListView)findViewById(android.R.id.list);
TextView emptyText = (TextView)findViewById(android.R.id.empty);
lv.setEmptyView(emptyText);
Then your ListView will automatically use this view when its adapter is empty
If you are using a ListActivity you do not need to call setEmptyView() on the ListView since the ListActivity automatically manages that for you.
Set a TextView and assign to it whatever you want to display when the ListView is empty:
ProjectListAdapter projectListAdapter = new ProjectListAdapter();
TextView empty=(TextView)findViewById(R.id.empty);
projectsListView.setEmptyView(empty);
And in my xml file we write the below code
<TextView
android:id="#+id/empty"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:text="Your text here"
android:textColor="#FFFFFF" />
I had this problem. You have to set the emptyView explicitly in your code.
Change your TextView:
<TextView
android:id="#+id/emptyResults"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/empty_list" />
Then in the onCreate():
listViewResults = (ListView) findViewById(R.id.list);
listViewResults.setEmptyView((LinearLayout) findViewById(R.id.emptyResults));
This code above assumes your ListView is in a LinearLayout.
I used ListFragment and had the same issue. I tried all variants from this answers, but the problem wasn't solved.
So I found my variant, to override setEmptyText():
public class NewsFragment extends ListFragment{
private TextView emptyText;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
//...
emptyText = (TextView)view.findViewById(android.R.id.empty);
//...
}
#Override
public void setEmptyText(CharSequence text) {
emptyText.setText(text);
}
}
Hope it will be helpful for somebody.
I know this is kind of late, but for it to work from XML, you need to put a weight on your ListView and have your TextView match_parent
<?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="match_parent"
android:orientation="vertical" >
<ListView
android:id="#android:id/list"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="1"
android:dividerHeight="1dp" >
</ListView>
<TextView
android:id="#android:id/empty"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="#string/empty_list" />
</LinearLayout>
There's a good example of how to do it which works awesome:
When you want to show a message to the user when the ListView is
empty, you have to keep in mind the following 3 steps:
In the xml where the ListView is declared, create a TextView (the TextView can be inside a LinearLayout if you want) right
below the ListView
Set the TextView’s id as “emptyElement”
And inside the activity, set the setEmptyView() property to the ListView
1- Create an xml which will hold the ListView and name it
“my_activity”
and an activity called “MyActivity”.
Now, in the just created xml “my_activity”, you will have to set the ListView. And right below the ListView, you will have to add
a TextView. This will be used to display the empty message.
Important: The TextView must have as id the following name: “emptyElement”. This name is mandatory. The message won’t be displayed
if you use another name.
This is how “my_activity” xml should look like:
<RelativeLayout 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:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="#dimen/activity_vertical_margin"
tools:context=".MyActivity">
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/listView"/>
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/emptyElement"
android:text="The list is empty"
android:textStyle="bold"
android:textSize="15sp"
android:visibility="gone"
android:layout_centerInParent="true"
android:textColor="#android:color/darker_gray"/>
</RelativeLayout>
Create an xml for displaying items (when the list is not empty), and name it “list_item”.
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/list_item_text_view"
android:textSize="20sp"
android:padding="10dp"
android:layout_marginLeft="5dp"/>
Create a new Java class for the custom adapter which will be used by the ListView and name “MyCustomAdapter”. The code for the adapter
is written below:
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
import java.util.ArrayList;
public class MyCustomAdapter extends BaseAdapter {
private ArrayList<String> mListItems;
private LayoutInflater mLayoutInflater;
public MyCustomAdapter(Context context, ArrayList<String> arrayList){
mListItems = arrayList;
//get the layout inflater
mLayoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public int getCount() {
//getCount() represents how many items are in the list
return mListItems.size();
}
#Override
//get the data of an item from a specific position
//i represents the position of the item in the list
public Object getItem(int i) {
return null;
}
#Override
//get the position id of the item from the list
public long getItemId(int i) {
return 0;
}
#Override
public View getView(int position, View view, ViewGroup viewGroup) {
// create a ViewHolder reference
ViewHolder holder;
//check to see if the reused view is null or not, if is not null then reuse it
if (view == null) {
holder = new ViewHolder();
view = mLayoutInflater.inflate(R.layout.list_item, null);
holder.itemName = (TextView) view.findViewById(R.id.list_item_text_view);
// the setTag is used to store the data within this view
view.setTag(holder);
} else {
// the getTag returns the viewHolder object set as a tag to the view
holder = (ViewHolder)view.getTag();
}
//get the string item from the position "position" from array list to put it on the TextView
String stringItem = mListItems.get(position);
if (stringItem != null) {
if (holder.itemName != null) {
//set the item name on the TextView
holder.itemName.setText(stringItem);
}
}
//this method must return the view corresponding to the data at the specified position.
return view;
}
/**
* Static class used to avoid the calling of "findViewById" every time the getView() method is called,
* because this can impact to your application performance when your list is too big. The class is static so it
* cache all the things inside once it's created.
*/
private static class ViewHolder {
protected TextView itemName;
}
}
Now go to MyActivity class and add the code below:
import android.app.Activity;
import android.os.Bundle;
import android.widget.ListView;
import java.util.ArrayList;
import java.util.List;
public class MyActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.my_activity);
ListView listView = (ListView) findViewById(R.id.listView);
// Create an empty array list of strings
List<String> items = new ArrayList<String>();
// Set the adapter
MyCustomAdapter adapter = new MyCustomAdapter(items);
listView.setAdapter(adapter);
// Set the emptyView to the ListView
listView.setEmptyView(findViewById(R.id.emptyElement));
}
}
TextView tv=(TextView) view.findViewById(R.id.empty);
tv.setVisibiliy(View.GONE);

Android Gallery with first thumbnail as coverpage

Thanks for reading!
Some background:
I am building a Gallery app from the tutorial here
Only change I made to this code is to replace
i.setLayoutParams(new Gallery.LayoutParams(150, 100));
with
i.setLayoutParams(new Gallery.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
to display only one gallery image at a time (Kinda like a slideshow viewer).
Problem:
I want the first thumbnail of the gallery to act as an Album Cover with two TextView's to display Album info.
Experiment:
So, I created an cover.xml like this:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:layout_height="fill_parent"
android:padding="6dip">
<ImageView android:id="#+cover/imgImage" android:adjustViewBounds="true"
android:layout_width="fill_parent" android:layout_height="fill_parent">
</ImageView>
<TextView android:id="#+cover/tvCoverText1"
android:layout_width="fill_parent" android:layout_height="wrap_content"
android:maxLines="2" android:text="Text1" />
<TextView android:id="#+cover/tvCoverText2"
android:layout_width="fill_parent" android:layout_height="wrap_content"
android:singleLine="true" android:maxLines="1" android:layout_below="#cover/tvCoverText1"
android:text="Text2" />
</RelativeLayout>
And here's the Java code. I check in getView() if the position is 0 (the first thumbnail) and then play around with the views.
package com.sagar.sample;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
import android.widget.Gallery;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
public class Main extends Activity {
private LayoutInflater mInflater = null;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Gallery g = (Gallery) findViewById(R.main.gallery);
g.setAdapter(new ImageAdapter(this));
g.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView parent, View v, int position, long id) {
Toast.makeText(Main.this, "" + position, Toast.LENGTH_SHORT).show();
}
});
}
public class ImageAdapter extends BaseAdapter {
int mGalleryItemBackground;
private Context mContext;
private Integer[] mImageIds = {
0, R.drawable.bp1, R.drawable.bp2, R.drawable.bp3
};
public ImageAdapter(Context c) {
mContext = c;
mInflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
// TypedArray a = obtainStyledAttributes(R.styleable.HelloGallery);
// mGalleryItemBackground = a.getResourceId(
// R.styleable.HelloGallery_android_galleryItemBackground, 0);
// a.recycle();
}
public int getCount() {
return mImageIds.length;
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder;
View view = convertView;
if(view == null) {
view = mInflater.inflate(R.layout.cover, null);
viewHolder = new ViewHolder();
viewHolder.tvCoverText1 = (TextView)view.findViewById(R.cover.tvCoverText1);
viewHolder.tvCoverText2 = (TextView)view.findViewById(R.cover.tvCoverText2);
viewHolder.imgView = (ImageView)view.findViewById(R.cover.imgImage);
view.setTag(viewHolder);
}
else {
viewHolder = (ViewHolder)view.getTag();
}
if(position == 0) {
viewHolder.tvCoverText1.setVisibility(View.VISIBLE);
viewHolder.tvCoverText2.setVisibility(View.VISIBLE);
viewHolder.imgView.setVisibility(View.GONE);
}
else {
viewHolder.tvCoverText1.setVisibility(View.GONE);
viewHolder.tvCoverText2.setVisibility(View.GONE);
viewHolder.imgView.setVisibility(View.VISIBLE);
//viewHolder.imgView = new ImageView(mContext);
viewHolder.imgView.setImageResource(mImageIds[position]); //Album cover is at 0th position
viewHolder.imgView.setLayoutParams(new Gallery.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
viewHolder.imgView.setScaleType(ImageView.ScaleType.FIT_XY);
viewHolder.imgView.setBackgroundResource(mGalleryItemBackground);
}
return view;
}
}
static class ViewHolder {
TextView tvCoverText1, tvCoverText2;
ImageView imgView;
}
}
End Result:
When the app loads up, I first see a blank screen for a while and then the view changes to display the AlbumCover. And it's painfully slow to scroll across the images.
Hmm..obviously, I am doing something wrong. I sincerely hope someone could help me here :(
Thanks!
UPDATE: Adding main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:layout_height="fill_parent">
<Gallery
android:id="#+main/gallery"
android:layout_width="fill_parent" android:layout_height="fill_parent"
/>
</RelativeLayout>
UPDATE2: So, here's some psuedo code to explain what I am trying to achieve:
if(position == 0)
//show toptext and bottomtext from cover.xml
else
//show tvTitle1 and tvTitle2 (may later include tvTitle3 and tvTitle4) from main.xml
Right now, only the position 0 case works and that too when I swipe to position 1 and swipe back to position 0 - the TextViews are grayed out and barely visible. :(
You need to set the text in your textviews everytime and not only when you inflate the view.
You should probably have 1 single layout file which holds the ui components in the gallery. Right now you have 2 TextView components which are independent of the Gallery. Instead, create some layout resource like this:
gallery_item.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ImageView
android:id="#+id/imageView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:adjustViewBounds="true"
android:background="#android:drawable/picture_frame"
android:layout_centerInParent="true" />
<TextView
android:id="#+main/tvTitle1" android:text="Title 1"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:layout_above="#+main/tvTitle2">
</TextView>
<TextView
android:id="#+main/tvTitle2" android:text="Title 2"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:layout_alignParentBottom="true" android:layout_alignParentLeft="true">
</TextView>
</RelativeLayout>
So in your getView:
View v = convertView;
if(v == null) {
LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.gallery_item, null);
holder = new ViewHolder();
holder.text1 = (TextView)v.findViewById(R.id.tvTitle1);
holder.text2 = (TextView)v.findViewById(R.id.tvTitle2);
holder.imageView = (ImageView)v.findViewById(R.id.imageView);
v.setTag(holder);
}
else
holder = (ViewHolder)v.getTag();
if(position == 0) {
holder.text1.setVisibility(View.VISIBLE);
holder.text2.setVisibility(View.VISIBLE);
holder.imageView.setVisibility(View.GONE);
}
else {
holder.text1.setVisibility(View.GONE);
holder.text2.setVisibility(View.GONE);
holder.imageView.setVisibility(View.VISIBLE);
}
return v;
You may find that there is some strange behavior going on when you scroll through items, so you might have to directly access each UI component rather than using the holder:
((TextView)v.findViewById(R.id.tvTitle1)).setVisibility(View.GONE);, etc
You also may be interested in setting different types of views for getView: http://developer.android.com/reference/android/widget/Adapter.html#getItemViewType(int)
After trying all approaches suggested here, I wasn't able to still get a custom gallery the way I wanted it to. I kept running into ClassCastException. So, here's what worked for me till now. This is just a workaround and incase someone comes up with a better way to design a custom gallery - do post your answer here so I can accept it.
Thanks for helping out!

Categories

Resources