I have a custom GridView populated by array of colors.
Now when I click the item I want to get the color of cell.
I have this code, but when I click the item, get the java.lang.NullPointerException.
public class Colori_picker extends Activity {
private GridView grColori;
private ColorPickerAdapter mAdapter;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.color_picker);
grColori= (GridView) findViewById(R.id.gridViewColors);
grColori.setAdapter(new ColorPickerAdapter(this));
grColori.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Object color = mAdapter.getItem(position);
finish();
}
});
}
the adapter
public class ColorPickerAdapter extends BaseAdapter {
private Context context;
// list which holds the colors to be displayed
private List<Integer> colorList = new ArrayList<Integer>();
// width of grid column
int colorGridColumnWidth;
public ColorPickerAdapter(Context context) {
this.context = context;
String colors[][] = {
{ "83334C", "B65775", "E07798", "F7A7C0", "FBC8D9", "FCDEE8" },
{ "000000", "434343", "666666", "999999", "CCCCCC", "EFEFEF" } };
colorList = new ArrayList<Integer>();
// add the color array to the list
for (int i = 0; i < colors.length; i++) {
for (int j = 0; j < colors[i].length; j++) {
colorList.add(Color.parseColor("#" + colors[i][j]));
}
}
}
public View getView(int position, View convertView, ViewGroup parent) {
ImageView imageView;
if (convertView == null) {
imageView = new ImageView(context);
// set the width of each color square
imageView.setLayoutParams(new GridView.LayoutParams(colorGridColumnWidth, colorGridColumnWidth));
} else {
imageView = (ImageView) convertView;
}
imageView.setBackgroundColor(colorList.get(position));
imageView.setId(position);
return imageView;
}
public int getCount() {
return colorList.size();
}
public Object getItem(int position) {
return null;
}
public long getItemId(int position) {
return 0;
}
}
What is happening is that you are declaring the instance variable mAdapter but never instantiating it. All you need to do is change this
grColori.setAdapter(new ColorPickerAdapter(this));
To this
mAdapter = new ColorPickerAdapter(this);
grColori.setAdapter(mAdapter);
Related
I want to saveInstance when changing from portrait to landscape. But when I try to restoreInstance of my letter button's background and enable, it tells me this error.
The program went well when I comment out those codes.
This is letter class
public class Letter extends BaseAdapter {
private String[] letters;
private LayoutInflater letterInf;
public Letter(Context c){
letters = new String[26];
for(int a = 0; a < letters.length; a++){
letters[a] = ""+(char)(a+'A');
}
letterInf = LayoutInflater.from(c);
}
#Override
public int getCount() {
return letters.length;
}
#Override
public Object getItem(int position) {
return null;
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
Button btnLetter;
if(convertView == null){
btnLetter = (Button) letterInf.inflate(R.layout.letter, null, false);
}else{
btnLetter = (Button) convertView;
}
btnLetter.setText(letters[position]);
return btnLetter;
}
}
This is what I try to restore onRestoreInstance (the whole version)
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
currPart = savedInstanceState.getInt("currPart");
numChars = savedInstanceState.getInt("numChars");
numCorr = savedInstanceState.getInt("numCorr");
int[] savedBodyPartVisibility = savedInstanceState.getIntArray("bodyPartVisibility");
for(int i = 0; i<savedBodyPartVisibility.length; i++){
bodyParts[i].setVisibility(savedBodyPartVisibility[i]);
}
//saved word
currWord = savedInstanceState.getString("currWord");
hint = savedInstanceState.getString("hint");
if(getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE){//get orientation
tvHint.setText("Hint:"+hint);// if landscape, show hint
//Toast.makeText(getBaseContext(), "This is landscape!", Toast.LENGTH_SHORT).show();
}
charViews = new TextView[currWord.length()];
wordLayout.removeAllViews();
for(int c = 0; c<currWord.length(); c++){
charViews[c] = new TextView(this);
charViews[c].setText(""+currWord.charAt(c));
charViews[c].setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
charViews[c].setGravity(Gravity.CENTER);
charViews[c].setTextColor(Color.WHITE);
charViews[c].setBackgroundResource(R.drawable.letter_bg);
wordLayout.addView(charViews[c]);
}
//saved charView
int[] savedCharViewColor = savedInstanceState.getIntArray("charViewColor");
for(int i = 0; i< savedCharViewColor.length; i++){
charViews[i].setTextColor(savedCharViewColor[i]);
}
//int numLetters = savedInstanceState.getInt("numLetters");
//letter enable//letter button background color
boolean[] savedLetterEnable = savedInstanceState.getBooleanArray("letterEnable");
int[] savedLettersColor = savedInstanceState.getIntArray("lettersColor");
for(int i = 0; i<savedLetterEnable.length; i++){
letters.getChildAt(i).setEnabled(savedLetterEnable[i]);
//letters.getChildAt(i).setBackgroundColor(savedLettersColor[i]);
}
}
You cannot restore it this way because views are recycled in RecyclerView/ListView. It means that only some of them is rendered and when you scroll it reuses already rendered views.
So in most of the cases it will not have that many child views as items in datasource.
The proper approach is to store information about items' state inside adapter.
I have created simple example to give you an idea how could it look. Note that setOnSelectedListener(new OnSelectedListener(){...} is fake code and you should write proper listener (onClick, or if you want to use Checkboxes then onCheckedCHange or anything else based on your needs).
public class Letter extends BaseAdapter {
private String[] letters;
private LayoutInflater letterInf;
private Set<String> selectedLetters = new ArraySet();
public Letter(Context c){
letters = new String[26];
for(int a = 0; a < letters.length; a++){
letters[a] = ""+(char)(a+'A');
}
letterInf = LayoutInflater.from(c);
}
Set<String> getState() {
return selectedLetters;
}
void restoreState(Set<String> selectedLetters) {
this.selectedLetters = selectedLetters;
notifyDataSetInvalidated();
}
#Override
public int getCount() {
return letters.length;
}
#Override
public Object getItem(int position) {
return null;
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
Button btnLetter;
if(convertView == null){
btnLetter = (Button) letterInf.inflate(R.layout.letter, null, false);
}else{
btnLetter = (Button) convertView;
}
if(selectedLetters.contains(letters[position])) {
btnLetter.setSelected(true);
} else {
btnLetter.setSelected(false);
}
btnLetter.setOnSelectedListener(new OnSelectedListener() {
void onSelected(..., boolean isSelected) {
if(isSelected) {
selectedLetters.add(letters[position]);
} else {
selectedLetters.remove(letters[position]);
}
}
});
btnLetter.setText(letters[position]);
return btnLetter;
}
}
Then whenever you save state, you get it from adapter getState and put it in savedInstanceState.
Whenever you restore state you get it from savedState and put in adapter restoreState
I have an array of 3 elements which I try to draw in a listview. The issue is that it only draws the first entry because getView always returns a position = 0.
Why is that? What do I do wrong?
my main java (fragment):
public class PSGlobalFragment extends Fragment {
List<PSGitem> listPSGitem;
ListView list;
PSGadaptater psgAdapter;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.psglobal, container, false);
}
#Override
public void onActivityCreated(final Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
String ip;
listPSGitem = new ArrayList<>();
psgAdapter = new PSGadaptater(getActivity(), listPSGitem);
listPSGitem.clear();
StoreDevDiscovery store = new StoreDevDiscovery();
// this is where I store the data
int count = store.getMax();
for(int i=0;i<count;i++){
ip = store.getIPDiscovery(i);
PSGitem item = new PSGitem();
item.setIp(ip);
listPSGitem.add(item);
list.setAdapter(psgAdapter);
}
}
and my adapter:
public class PSGadaptater extends BaseAdapter {
private int size = 0;
private List<PSGitem> listIp;
private LayoutInflater layoutInflater;
Context context;
public PSGadaptater(Context c, List<PSGitem> objects) {
context = c;
listIp = objects;
layoutInflater = LayoutInflater.from(context);
}
#Override
public void notifyDataSetChanged() {
size = listIp.size();
super.notifyDataSetChanged();
}
#Override
public int getCount() {
return listIp.size();
}
public Object getItem(int position) {
return listIp.get(position);
}
public long getItemId(int position) {
return position;
}
private class ViewIPHolder {
TextView ip_psg;
}
public View getView(int position, View convertView, ViewGroup parent) {
ViewIPHolder viewHolder;
if(convertView == null) {
viewHolder = new ViewIPHolder();
convertView = layoutInflater.inflate(R.layout.listview_item_psg, null);
viewHolder.ip_psg = (TextView) convertView.findViewById(R.id.ipaddr_psg);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewIPHolder) convertView.getTag();
}
viewHolder.ip_psg.setText(listIp.get(position).getIpaddr());
// position always = 0 this is my issue
return convertView;
}
}
and the PSCitem.java:
public class PSGitem {
private String ip1;
public String getIp(){
return ip1;
}
public void setIp(String ip){
ip1 = ip;
}
}
The problem is that you are creating your Adapter from an empty set of items:
listPSGitem = new ArrayList<>();
psgAdapter = new PSGadaptater(getActivity(), listPSGitem);
If you wish to add items to the adapter later, you should add the items to the adapter listIp list variable, and then let the adapter know about this change with notifyDataSetChanged() method.
Change your onActivityCreated method like below.
#Override
public void onActivityCreated(final Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
String ip;
listPSGitem = new ArrayList<>();
listPSGitem.clear();
StoreDevDiscovery store = new StoreDevDiscovery();
// this is where I store the data
int count = store.getMax();
for(int i=0;i<count;i++){
ip = store.getIPDiscovery(i);
PSGitem item = new PSGitem();
item.setIp(ip);
listPSGitem.add(item);
}
psgAdapter = new PSGadaptater(getActivity(), listPSGitem);
list.setAdapter(psgAdapter);
}
I have list view. I want to change color of clicked row. But only 0,1 and 2 indexes are correctly colored others are not working properly likewise if i clicked on 4th row the 5th one row color changes and sometimes if i clicked on 7th row then none of row is colored. Please Help
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View v,final int position, long id) {
for (int i = 0; i < lv.getChildCount(); i++) {
if(position == i ){
lv.getChildAt(i).setBackgroundColor(Color.BLUE);
}else{
lv.getChildAt(i).setBackgroundColor(Color.TRANSPARENT);
}
}
public abstract class CustomAdapter extends BaseAdapter implements SeekBar.OnSeekBarChangeListener {
Context context;
ArrayList<HashMap<String, String>> countryList;
ArrayList<HashMap<String, String>> mStringFilterList;
LayoutInflater inflter;
public ImageView img2,img3;
Handler mHandler = new Handler();
SeekBar songProgressBar;
SelfUpdatingSeekbar self;
public boolean isStarted = true;
public static final int UPDATE_FREQUENCY = 500;
public static final int STEP_VALUE = 4000;
public final Handler handler = new Handler();
public final Runnable updatePositionRunnable = new Runnable() {
public void run() {
updatePosition();
}
};
public CustomAdapter(Context applicationContext, ArrayList<HashMap<String, String>> countryList) {
this.context = applicationContext;
this.countryList = countryList;
mStringFilterList = countryList;
inflter = (LayoutInflater.from(applicationContext));
}
#Override
public int getCount() {
return countryList.size();
}
public void updateData(ArrayList<HashMap<String, String>> countryList) {
this.countryList = countryList;
notifyDataSetChanged();
}
#Override
public Object getItem(int i) {
return null;
}
#Override
public long getItemId(int i) {
return 0;
}
#Override
public View getView(final int position, View view, ViewGroup viewGroup) {
view = inflter.inflate(R.layout.list_itemss, null);
view.setTag(position);
String hello = String.valueOf(countryList.get(position));
String s = hello;
int s1 = s.lastIndexOf("=");
int s2 = s.lastIndexOf("}");
strSub = s.substring(s1+1,s2/*s.lastIndexOf("=")*/);
Log.d("Hello",hello);
String henno1 = String.valueOf(hello.length());
Log.d("hellya",strSub);
TextView country = (TextView) view.findViewById(R.id.textView);
country.setText(strSub);
uniqueItemIdCount = countryList.size();
Log.d("PrintIdss", String.valueOf(uniqueItemIdCount));
ImageView twitt = (ImageView)view.findViewById(R.id.button5);
twitt.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
TweetComposer.Builder builder = new TweetComposer.Builder(context)
.text(strSub);
builder.show();
}
});
ImageView fb = (ImageView)view.findViewById(R.id.button6);
fb.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
ShareLinkContent linkContent = new ShareLinkContent.Builder()
.setContentTitle(strSub)
.setContentDescription(
"Top Hollywood Songs")
.setContentUrl(Uri.parse("http://www.moremovies.com/"))
.build();
shareDialog.show(linkContent);
}
});
songProgressBar = (SeekBar) view.findViewById(R.id.songProgressBar);
songProgressBar.setOnSeekBarChangeListener(this);
songCurrentDurationLabel = (TextView)view.findViewById(R.id.songCurrentDurationLabel);
songTotalDurationLabel = (TextView)view.findViewById(R.id.songTotalDurationLabel);
img2 = (ImageView)view.findViewById(R.id.button3);
img2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
int songIndex = position;
String hellos = String.valueOf(countryList.get(songIndex));
int s1 = hellos.lastIndexOf("=");
int s2 = hellos.lastIndexOf("}");
String strSubs = hellos.substring(s1+1,s2/*s.lastIndexOf("=")*/);
selelctedFile.setText(strSubs);
currentSongIndex=songIndex;
playSong(currentSongIndex);
}
});
}
You have to manage the position and the background of yourself because in your adapter as you are reusing the cell. Kindly check your adapter you will get it.
And to achieve what you want. You have to update your adapter and implement the click listener in the Adapter view.
Try to subtract the position of your listview:
for (int i = 0; i < lv.getChildCount(); i++) {
if(position - lv.getFirstVisiblePosition() == i ){ //<-Here
lv.getChildAt(i).setBackgroundColor(Color.BLUE);
}else{
lv.getChildAt(i).setBackgroundColor(Color.TRANSPARENT);
}
}
You need to implement the two background options, because the adapter will reuse your layout.
So you need to keep track of the selected items (not layouts), as i see you are using a HashMap to populate your adapter so, create a List with the selected positions and when you are populating your adapter do something like :
//Globals Variables
List<int> SelectedList = new ArrayList<>();
//On select event
SelectedList.add(position);
//On deselect event
SelectedList.remove(position);
//On get view
if(SelectedList.contains(position){
// Background selected
}else{
// Explicit set the background to the default
}
If you want to start with play buttons and on click change to pause the one clicked and all others back to play then inside your adapter where you initialize the play/pause button do :
playPause.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View v,final int position, long id) {
for (int i = 0; i < lv.getChildCount(); i++) {
Button PlayPause = v.findViewById(R.id.play_pause_button)
ButtonPlayPause.setImageResource("play resource")
}
playPause.setImageResource("pause resource")
}
}
}
});
Code may have some syntax errors but you get the idea.
There's a system visual effect everytime you click a view in Android. In Lollipop it's the ripple effect. When I created a ListView and associated it to an ordinary ArrayAdapter, this effect was present. Now that I've added a custom ListView, this effect is lost.
Now, I've tried to isolate what the problem is, and since using the same list item layout with a default adapter worked nicely, I would say that the problem is on my custom adapter.
I've seen many solutions related to this case that just implemented the ripple effect calling some drawables; this is not what I'm trying to do. The ripple effect shows only because I'm running the app on Android 5, now what I want to do is to have the default system highlight effect for my items when they're being clicked.
Here are the (hopefully) related pieces of my custom adapter:
public class CustomCardSetsAdapter extends BaseAdapter {
List<Card> totalList;
ArrayList<Boolean> hiddenItems;
ListView parentLV;
Integer curPosition = -1;
public static int selectedRowIndex;
public CustomCardSetsAdapter(CardSets cardList, ListView parentListView)
{
this.parentLV = parentListView;
assignSetValues(cardList);
totalList = cardList.getBlackrockMountain();
totalList.addAll(cardList.getClassic());
totalList.addAll(cardList.getCurseofNaxxramas());
totalList.addAll(cardList.getGoblinsvsGnomes());
Collections.sort(totalList,
new Comparator<Card>() {
public int compare(Card f1, Card f2) {
return f1.toString().compareTo(f2.toString());
}
});
hiddenItems = new ArrayList<>();
for (int i = 0; i < totalList.size(); i++) {
if(!totalList.get(i).getCollectible())
hiddenItems.add(true);
else
hiddenItems.add(false);
}
}
#Override
public int getCount() {
return (totalList.size() - getHiddenCount());
}
#Override
public View getView(final int position, View convertView, final ViewGroup parent) {
final int index = getRealPosition(position);
if(convertView == null) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
convertView = inflater.inflate(R.layout.card_list_item, parentLV, false);
}
convertView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Integer prevPosition = curPosition;
curPosition = position;
if(prevPosition >= parentLV.getFirstVisiblePosition() &&
prevPosition <= parentLV.getLastVisiblePosition())
{
View view = parentLV.getChildAt(prevPosition- parentLV.getFirstVisiblePosition());
parentLV.getAdapter().getView(prevPosition,view, parentLV);
}
v.setBackgroundColor(Color.WHITE);
}
});
Card curCard = totalList.get(index);
TextView cardName = (TextView) convertView.findViewById(R.id.cardName);
cardName.setText(curCard.getName());
setRarityColor(curCard,cardName);
TextView manaCost = (TextView) convertView.findViewById(R.id.manaCost);
manaCost.setText((curCard.getCost()).toString());
ImageView setIcon = (ImageView) convertView.findViewById(R.id.setIcon);
setSetIcon(curCard,setIcon);
if(position == curPosition)
convertView.setBackgroundColor(Color.WHITE);
else
convertView.setBackgroundColor(Color.TRANSPARENT);
return convertView;
}
#Override
public int getItemViewType(int position) {
return R.layout.card_list_item;
}
#Override
public int getViewTypeCount() {
return 1;
}
#Override
public boolean isEmpty() {
return false;
}
private int getHiddenCount()
{
int count = 0;
for(int i = 0;i <totalList.size();i++)
if(hiddenItems.get(i))
count++;
return count;
}
private int getRealPosition(int position) {
int hElements = getHiddenCountUpTo(position);
int diff = 0;
for(int i=0;i<hElements;i++) {
diff++;
if(hiddenItems.get(position+diff))
i--;
}
return (position + diff);
}
private int getHiddenCountUpTo(int location) {
int count = 0;
for(int i=0;i<=location;i++) {
if(hiddenItems.get(i))
count++;
}
return count;
}
}
Thanks in advance.
in your ListView XML, add:
android:drawSelectorOnTop="true"
I also think you are using your adapter wrong...
Use the ViewHolder Pattern on your Adapter:
public class CustomCardSetsAdapter extends BaseAdapter {
List<Card> totalList;
ArrayList<Boolean> hiddenItems;
ListView parentLV;
Integer curPosition = -1;
public static int selectedRowIndex;
private class ViewHolderRow{
TextView cardName;
TextView manaCost;
ImageView setIcon;
}
public CustomCardSetsAdapter(CardSets cardList, ListView parentListView)
{
this.parentLV = parentListView;
assignSetValues(cardList);
totalList = cardList.getBlackrockMountain();
totalList.addAll(cardList.getClassic());
totalList.addAll(cardList.getCurseofNaxxramas());
totalList.addAll(cardList.getGoblinsvsGnomes());
Collections.sort(totalList,
new Comparator<Card>() {
public int compare(Card f1, Card f2) {
return f1.toString().compareTo(f2.toString());
}
});
hiddenItems = new ArrayList<>();
for (int i = 0; i < totalList.size(); i++) {
if(!totalList.get(i).getCollectible())
hiddenItems.add(true);
else
hiddenItems.add(false);
}
}
#Override
public int getCount() {
return (totalList.size() - getHiddenCount());
}
#Override
public View getView(final int position, View convertView, final ViewGroup parent) {
final int index = getRealPosition(position);
ViewHolderRow theRow;
if(convertView == null) {
theRow = new ViewHolderRow();
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
convertView = inflater.inflate(R.layout.card_list_item, parentLV, false);
// Cache your views
theRow.cardName = (TextView) convertView.findViewById(R.id.cardName);
theRow.manaCost = (TextView) convertView.findViewById(R.id.manaCost);
theRow.setIcon = (ImageView) convertView.findViewById(R.id.setIcon);
// Set the Tag to the ViewHolderRow
convertView.setTag(theRow);
}else{
// get the Row to re-use
theRow = (ViewHolderRow) convertView.getTag();
}
//... Removed convertView.setOnClickListener
Card curCard = totalList.get(index);
// Set Items
theRow.cardName.setText(curCard.getName());
setRarityColor(curCard,theRow.cardName);
theRow.manaCost.setText((curCard.getCost()).toString());
setSetIcon(curCard,theRow.setIcon);
if(position == curPosition){
convertView.setBackgroundColor(Color.WHITE);
}else{
convertView.setBackgroundColor(Color.TRANSPARENT);
}
return convertView;
}
#Override
public int getItemViewType(int position) {
return R.layout.card_list_item;
}
#Override
public int getViewTypeCount() {
return 1;
}
#Override
public boolean isEmpty() {
return false;
}
private int getHiddenCount()
{
int count = 0;
for(int i = 0;i <totalList.size();i++)
if(hiddenItems.get(i))
count++;
return count;
}
private int getRealPosition(int position) {
int hElements = getHiddenCountUpTo(position);
int diff = 0;
for(int i=0;i<hElements;i++) {
diff++;
if(hiddenItems.get(position+diff))
i--;
}
return (position + diff);
}
private int getHiddenCountUpTo(int location) {
int count = 0;
for(int i=0;i<=location;i++) {
if(hiddenItems.get(i))
count++;
}
return count;
}
}
Set an onListItemClickListener instead of using this on the entire convertView...
yourListView.setOnItemClickListener(ListListener);
private final OnItemClickListener ListListener = new OnItemClickListener{
#Override
public void onItemClick(AdapterView<?> arg0, View view, int position, long arg3) {
// ... Do something on click
}
}
I have a very strange problem while using my ListView.
Only a part of my adapter items are renderd in the listview on screen but when I interact with the listview (ie tries to scroll it) all items are renderd properly.
This fenonemon only occurs if i have less items than the screen can show. Take a look at these screenshots below.
Before interaction:
After interaction:
Source code of activity where adding items:
String[] jRests = getResources().getStringArray(R.array.j_restaurants);
String[] lRests = getResources().getStringArray(R.array.l_restaurants);
items = new ArrayList<Object>();
items.add(getString(R.string.campus_j));
for(String item : jRests){
String[] val = item.split(",,,");
items.add(new FoodSectionListItem(new Restaurant(val[0], val[1], val[2], "")));
}
items.add(getString(R.string.campus_l));
for(String item : lRests){
String[] val = item.split(",,,");
items.add(new FoodSectionListItem(new Restaurant(val[0], val[1], val[2], "")));
}
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
adapter = new BaseSectionAdapter(this, R.layout.list_item_fragment_header);
if(!isTabletView()){
adapter.setSelectedItem(-1);
}
adapter.setItems(items);
Code of adapter:
public class BaseSectionAdapter extends AmazingAdapter {
private LayoutInflater inflater;
private int selectedItem = 0;
private List<Object> items;
private List<SectionItem> sections = new ArrayList<SectionItem>(10);
private List<Class> itemTypes = new ArrayList<Class>();
private List<Integer> sectionPositions = new ArrayList<Integer>();
private int listHeaderLayoutId;
private View headerView;
public static interface ISectionListItem {
public void setProps(View convertView, int position, int selectedItem);
public View getLayout(LayoutInflater inflater);
}
private class SectionItem implements Serializable {
private static final long serialVersionUID = -8930010937740160935L;
String text;
int position;
public SectionItem(String text, int position) {
this.text = text;
this.position = position;
}
}
public BaseSectionAdapter(Context context, int listHeaderLayoutId) {
this.listHeaderLayoutId = listHeaderLayoutId;
init(context);
}
public BaseSectionAdapter(Context context, int listHeaderLayoutId, List<Object> listItems) {
this.listHeaderLayoutId = listHeaderLayoutId;
init(context);
initListItems(listItems);
}
private void init(Context context) {
inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
public void setSelectedItem(int position) {
selectedItem = position;
}
// public List<ListItem> getItems() {
// return items;
// }
private void initListItems(List<Object> itemList) {
int curSection = -1;
//int curPosition = 0;
//curSection = 0;
this.items = itemList;
itemTypes.clear();
sections.clear();
sectionPositions.clear();
int listSize = itemList.size();
for(int i = 0; i < listSize; i++){
Object currentItem = items.get(i);
if(currentItem instanceof String){
sections.add(new SectionItem((String) currentItem,i));
curSection++;
}
if(!itemTypes.contains(currentItem.getClass())){
itemTypes.add(currentItem.getClass());
}
sectionPositions.add(curSection);
}
Log.d("test", "No of items = "+items.size());
Log.d("test", "No of itemtypes = "+itemTypes.size());
Log.d("test", "View type count = "+getViewTypeCount());
}
public void setItems(List<Object> itemList) {
initListItems(itemList);
}
public int getCount() {
return items==null?0:items.size();
}
#Override
public int getViewTypeCount(){
return (itemTypes.size() == 0)?1:itemTypes.size();
}
#Override
public int getItemViewType(int position){
return itemTypes.indexOf(items.get(position).getClass());
}
#Override
public boolean isEnabled(int position){
return !(items.get(position) instanceof String || items.get(position) instanceof EmptySectionListItem);
}
#Override
public Object getItem(int position) {
return items.get(position);
}
public long getItemId(int position) {
return position;
}
#Override
protected void onNextPageRequested(int page) {
// TODO Auto-generated method stub
}
#Override
protected void bindSectionHeader(View view, int position,
boolean displaySectionHeader) {
// TextView lSectionTitle = (TextView) view
// .findViewById(R.id.txt_list_header);
// if (displaySectionHeader) {
// lSectionTitle.setVisibility(View.VISIBLE);
// lSectionTitle
// .setText(getSections()[getSectionForPosition(position)]);
// } else {
// lSectionTitle.setVisibility(View.GONE);
// }
}
#Override
public View getAmazingView(int position, View convertView, ViewGroup parent) {
Object curItemObject = items.get(position);
boolean isHeader = (curItemObject instanceof String);
if(convertView == null){
if(isHeader && headerView != null){
convertView = headerView;
}else if(isHeader){
convertView = inflater.inflate(listHeaderLayoutId, null);
headerView = convertView;
}else{
convertView = ((ISectionListItem) curItemObject).getLayout(inflater);
}
}
if(isHeader){
TextView header = ((TextView)convertView.findViewById(R.id.txt_list_header));
header.setText((String)curItemObject);
}else{
((ISectionListItem)curItemObject).setProps(convertView, position, selectedItem);
}
return convertView;
}
#Override
public void configurePinnedHeader(View header, int position, int alpha) {
TextView textView = ((TextView)header.findViewById(R.id.txt_list_header));
textView.setText(getSections()[getSectionForPosition(position)]);
}
#Override
public int getPositionForSection(int section) {
if(section >= sections.size()){
return 0;
}
return sections.get(section).position;
}
#Override
public int getSectionForPosition(int position) {
return sectionPositions.get(position);
}
#Override
public String[] getSections() {
String[] res = new String[sections.size()];
for (int i = 0; i < res.length; i++) {
res[i] = sections.get(i).text;
}
return res;
}
}
Code of layout:
LinearLayout layout = new LinearLayout(this);
layout.setOrientation(LinearLayout.HORIZONTAL);
FrameLayout listLayout = new FrameLayout(this);
LinearLayout.LayoutParams listParams = new LinearLayout.LayoutParams(0, FrameLayout.LayoutParams.MATCH_PARENT);
listParams.weight = 1;
listLayout.setId(LIST_FRAGMENT_VIEW_ID);
FrameLayout detailLayout = new FrameLayout(this);
LinearLayout.LayoutParams detailParams = new LinearLayout.LayoutParams(0, FrameLayout.LayoutParams.MATCH_PARENT);
detailParams.weight = 2;
detailLayout.setId(DETAIL_FRAGMENT_VIEW_ID);
layout.addView(listLayout, listParams);
layout.addView(detailLayout, detailParams);
if(savedInstanceState == null){
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.add(listLayout.getId(), (Fragment) listFragment, TWO_PANEL_LIST_FRAGMENT_TAG);
ft.add(detailLayout.getId(), detailFragment);
ft.commit();
}
setContentView(layout);
try calling notifyDataSetChanged() in runOnUIThread() method like I have shown below and it will work like a charm. :)
runOnUiThread(new Runnable() {
#Override
public void run() {
messageAdapter.notifyDataSetChanged();
}
});
i dont know what causes the problem, but if you don't find a logical solution to it you could try something like this:
trigger an onTouchEvent() programmatically whenever you launch the ListView.
scroll down and back up programmatically as soon as the ListView is launched.
etc..
Add ListView widget to layout.xml and add content of list to that. Do not use FrameLayout as it probably is the cause of the problem. It is updating content after touch so the Layout it is on is no implementing the correct onCreate() setup as the ListView widget has.
Are you calling the method notifyDataSetChanged() on your adapter after adding new items? This causes the listview to refresh its view when the underlying dataset is changed.
If it still doesn't work, try notifyDataSetInvalidated() that causes the listview to redraw completely.
Solved it!!!
Problem was with the adapter trying to reuse the same section item. Not good!!!
Changed it to inflate the section item each time we hit a section!