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
}
}
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
This loop return only visible position values.However I need the values of child items that are invisible.
for (int i = 0; i < material_issue_list.getCount(); i++) {
View layout = materialIssueAdapter.getViewByPositio(i, material_issue_list);
LinearLayout listItem = (LinearLayout) materialIssueAdapter.getViewByPositio(i, material_issue_list);
String batchSTR = ((AutoCompleteTextView) listItem.findViewById(R.id.batch_AutoComplete)).getText().toString();
String qtySTR = ((EditText) listItem.findViewById(R.id.issue_qty_ETD)).getText().toString();}
My full adapter class,Some one help me suggest to get the correct output.My problem I'm getting null values from the views that are invisible.
Only the visible values are being updated to arraylist.
Thanks in advance.
public class IssueMaterialAdapter extends BaseAdapter {
private Activity activity;
public static ArrayList Dummylist;
private static LayoutInflater inflater = null;
public Resources res;
public static ArrayList<BatchNav> batchNavs_Arr;
static ArrayList<String> batch_Arr;
public static ArrayList<String> batch_data;
public static ArrayList<String> issue_qty;
LinkedHashSet<String> hashSet;
public static ArrayList<BatchModel> batchModels = new ArrayList<BatchModel>();
public static HashMap<ViewHolder, String> batch_map;
public static HashMap<ViewHolder, String> qty_map;
HashMap<String, String> mValues = new HashMap<String, String>();
ArrayList<SaveDataModel> saveDataModels;
public IssueMaterialAdapter(Activity a, ArrayList dummy) {
activity = a;
Dummylist = dummy;
loadBatch();
this.batch_map = new HashMap<>();
inflater = (LayoutInflater) activity.
getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public int getCount() {
if (Dummylist.size() <= 0)
return 1;
return Dummylist.size();
}
#Override
public int getItemViewType(int position) {
return position;
}
#Override
public Object getItem(int position) {
return position;
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
View vi = convertView;
final ViewHolder holder;
if (convertView == null) {
vi = inflater.inflate(R.layout.material_issue_details_list, null);
holder = new ViewHolder();
holder.batch = (AutoCompleteTextView) vi.findViewById(R.id.batch_AutoComplete);
holder.issue = (EditText) vi.findViewById(R.id.issue_qty_ET);
holder.material_descrption = (TextView) vi.findViewById(R.id.material_desc);
holder.unit_issue = (EditText) vi.findViewById(R.id.unit_issue_ET);
holder.matnr = (TextView) vi.findViewById(R.id.matnr);
holder.prdgrp = (TextView) vi.findViewById(R.id.prod_grp);
vi.setTag(holder);
batch_map.put(holder, "");
FilterWithSpaceAdapter<String> farmer_co_no_adapter = new FilterWithSpaceAdapter<String>(activity,
R.layout.custom_items, batch_Arr);
holder.batch.setAdapter(farmer_co_no_adapter);
holder.batch.setThreshold(1);
vi.setTag(holder);
} else {
holder = (ViewHolder) vi.getTag();
}
if (Dummylist.size() == AgriDistributionActivity.get_materials.size()) {
holder.material_descrption.setText(AgriDistributionActivity.get_materials.get(position));
holder.matnr.setText(AgriDistributionActivity.get_matnr.get(position));
holder.prdgrp.setText(AgriDistributionActivity.selected_prdgrp.get(position));
}
try {
if (saveDataArr.size() > 0) {
holder.batch.setText(saveDataArr.get(position).getBatch());
holder.issue.setText(saveDataArr.get(position).getQty());
holder.unit_issue.setText(saveDataArr.get(position).getQty_uom());
}
} catch (Exception e) {
}
return vi;
}
public static class ViewHolder {
public EditText issue, unit_issue;
public AutoCompleteTextView batch;
public TextView material_descrption, matnr,prdgrp;
}
private void loadBatch() {
batch_Arr = new ArrayList<String>();
batchNavs_Arr = new ArrayList<BatchNav>();
hashSet = new LinkedHashSet<>();
BatchNavEntityCollection batchNavEntityCollection = BatchNavEntityCollection.getInstance();
batchNavs_Arr = batchNavEntityCollection.getBatchOutVal();
for (int i = 0; i < batchNavs_Arr.size(); i++) {
String batch = batchNavs_Arr.get(i).getCharg();
batch_Arr.add(batch);
hashSet.addAll(batch_Arr);
batch_Arr.clear();
batch_Arr.addAll(hashSet);
}
}
public View getViewByPositio(int position, ListView listView) {
final int firstListItemPosition = listView.getFirstVisiblePosition();
final int lastListItemPosition = firstListItemPosition + listView.getChildCount() - 1;
if (position < firstListItemPosition || position > lastListItemPosition) {
return listView.getAdapter().getView(position, null, listView);
} else {
final int childIndex = position - firstListItemPosition;
return listView.getChildAt(childIndex);
}
}
}
You have saveDataArr list which holds all your data.
You can add a getter if you want to do it from an activity , add something like this to your adapter :
private SaveDataModelsendLog(int position) {
return saveDataArr(position);
}
That should do the trick , having said all that you should also look at the difference between static and non-static variables ,
it seems like you have to many of them ,
Enjoy.
I'm new to android. I have developed a calendar for my App and i want the user to be able to switch between months smoothly.
So I decided to use the ViewPager and to make it use unlimited amount of months i have implement this solution:
http://code.google.com/p/electricsleep/source/browse/trunk/src/com/androsz/electricsleepbeta/app/HistoryMonthActivity.java
Unfortunately it doesn't work for me. When I try to scroll left or right the next month to be showed comes until I scroll with the finger, but when i release my finger the earlier showed month comes again but the date on the indicator remains the right.
I post the code:
calendarView = new GridView(this);
calendarView.setLayoutParams(new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
calendarView.setNumColumns(7);
adapter = new GridCellAdapter(getApplicationContext(), R.id.calendar_day_gridcell, newdatum);
adapter.notifyDataSetChanged();
calendarView.setAdapter(adapter);
calendarView.setTag(newdatum.toString());
viewpager = (ViewPager) this.findViewById(R.id.calviewpager);
viewpager.setAdapter(new MonthPagerAdapter());
viewpager.setOffscreenPageLimit(3);
mTitleIndicator = (TitlePageIndicator) findViewById(R.id.indicator);
mTitleIndicator.setViewPager(viewpager, 1);
mTitleIndicator.setOnPageChangeListener(new PageListener());
}
private class PageListener implements OnPageChangeListener{
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageScrollStateChanged(int state) {
if (state == ViewPager.SCROLL_STATE_IDLE) {
final DateTime old0 = DateTime.parse(viewpager.getChildAt(0).getTag().toString());
final DateTime old1 = DateTime.parse(viewpager.getChildAt(1).getTag().toString());
final DateTime old2 = DateTime.parse(viewpager.getChildAt(2).getTag().toString());
if (focusedPage == 0) {
Log.d("FOCUSEDPAGE=0",newdatum.toString());
DateTime minus = new DateTime();
minus=old0.minusMonths(1);
viewpager.getChildAt(0).setTag(minus.toString());
viewpager.getChildAt(1).setTag(old2.toString());
viewpager.getChildAt(2).setTag(old1.toString());
}
else if (focusedPage == 2) {
Log.d("FOCUSEDPAGE=2",newdatum.toString());
DateTime plus = new DateTime();
plus=old2.plusMonths(1);
viewpager.getChildAt(0).setTag(old1.toString());
viewpager.getChildAt(1).setTag(old2.toString());
viewpager.getChildAt(2).setTag(plus.toString());
}
mTitleIndicator.setCurrentItem(1);
}
}
#Override
public void onPageSelected(int position) {
newdatum=DateTime.parse(viewpager.getChildAt(position).getTag().toString());
focusedPage = position;
}
}
private class MonthPagerAdapter extends PagerAdapter{
ViewPager container;
private GridView addMonthViewAt(int position, DateTime date) {
final GridView gv = new GridView(CalendarActivity.this);
gv.setLayoutParams(new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
gv.setNumColumns(7);
gv.setTag(date.toString());
setGridCellAdapterToDate(date, gv);
container.addView(gv, position);
return gv;
}
#Override
public void destroyItem(View container, int position, Object object) {
((ViewPager) container).removeViewAt(position);
}
#Override
public void finishUpdate(View container) {
}
#Override
public int getCount() {
return 3;
}
#Override
public Object instantiateItem(View container, int pos) {
this.container = (ViewPager) container;
DateTime newdate=newdatum.plusMonths(pos-1);
Log.d("INSTATIATE",newdate.toString());
return addMonthViewAt(pos, newdate);
}
#Override
public String getPageTitle(int position) {
final GridView gv = (GridView) container.getChildAt(position);
DateTime dt=DateTime.parse(gv.getTag().toString());
String title=dt.monthOfYear().getAsText()+" "+dt.getYear();
Log.d("GET PAGE TITLE",dt.toString());
return title;
}
#Override
public boolean isViewFromObject(View view, Object object) {
return view.equals(object);
}
#Override
public void restoreState(Parcelable state, ClassLoader loader) {
}
#Override
public Parcelable saveState() {
return null;
}
#Override
public void startUpdate(View container) {
}
}
private void setGridCellAdapterToDate(DateTime newdate, GridView gridview){
GridCellAdapter adapt = new GridCellAdapter(getApplicationContext(), R.id.calendar_day_gridcell, newdate);
adapt.notifyDataSetChanged();
gridview.setAdapter(adapt);
}
And the GridCellAdapter code:
public class GridCellAdapter extends BaseAdapter implements OnClickListener{
private final Context _context;
private final List<String> list;
private Button gridcell;
public GridCellAdapter(Context context, int textViewResourceId, DateTime datum){
super();
this._context = context;
this.list = new ArrayList<String>();
printMonth(datum);
}
public String getItem(int position){
return list.get(position);
}
public int getCount(){
return list.size();
}
private void printMonth(DateTime cal){
int daysInMonth = cal.dayOfMonth().getMaximumValue();
int daysInPrevMonth = cal.minusMonths(1).dayOfMonth().getMaximumValue()+1;
int trailingSpaces = cal.withDayOfMonth(1).dayOfWeek().get()-1;
SQLiteAdapter sql= new SQLiteAdapter(getApplicationContext());
sql.openToWrite(month(cal));
if(sql.tableExists()){
String back="blue";
for(int i=0;i<7;i++)
list.add("DAY:"+cal.withDayOfWeek(i+1).toString()+": ");
for (int i = 0; i < trailingSpaces; i++){
if(sql.rowExists(cal.minusMonths(1).withDayOfMonth((daysInPrevMonth-trailingSpaces)+i).toString("yyyy-MM-dd")))
back="green";
else back="blue";
list.add("GREY:"+cal.minusMonths(1).withDayOfMonth((daysInPrevMonth-trailingSpaces)+i).toString("yyyy-MM-dd")+": "+":"+back);
}
for (int i = 1; i <= daysInMonth; i++){
if(sql.rowExists(cal.withDayOfMonth(i).toString("yyyy-MM-dd")))
back="green";
else back="blue";
if (cal.withDayOfMonth(i).toString("yyyy-MM-dd").equals(DateTime.now().toString("yyyy-MM-dd"))){
list.add("WHITE:"+cal.withDayOfMonth(i).toString("yyyy-MM-dd")+":"+checkIsFeiertag(cal.withDayOfMonth(i)).toString()+":"+back);
}
else{
checkIsFeiertag(cal.withDayOfMonth(i));
list.add("BLUE:"+cal.withDayOfMonth(i).toString("yyyy-MM-dd")+":"+checkIsFeiertag(cal.withDayOfMonth(i)).toString()+":"+back);
}
}
for (int i = 0; i < list.size() % 7; i++){
if(sql.rowExists(cal.plusMonths(1).withDayOfMonth(i+1).toString("yyyy-MM-dd")))
back="green";
else back="blue";
list.add("GREY:"+cal.plusMonths(1).withDayOfMonth(i+1).toString("yyyy-MM-dd")+": "+":"+back);
}
}
else{
for(int i=0;i<7;i++)
list.add("DAY:"+cal.withDayOfWeek(i+1).toString()+": "+": ");
for (int i = 0; i < trailingSpaces; i++){
list.add("GREY:"+cal.minusMonths(1).withDayOfMonth((daysInPrevMonth-trailingSpaces)+i).toString("yyyy-MM-dd")+": "+": ");
}
for (int i = 1; i <= daysInMonth; i++){
if (cal.withDayOfMonth(i).toString("yyyy-MM-dd").equals(DateTime.now().toString("yyyy-MM-dd"))){
list.add("WHITE:"+cal.withDayOfMonth(i).toString("yyyy-MM-dd")+":"+checkIsFeiertag(cal.withDayOfMonth(i)).toString()+": ");
}
else{
checkIsFeiertag(cal.withDayOfMonth(i));
list.add("BLUE:"+cal.withDayOfMonth(i).toString("yyyy-MM-dd")+":"+checkIsFeiertag(cal.withDayOfMonth(i)).toString()+": ");
}
}
for (int i = 0; i < list.size() % 7; i++){
list.add("GREY:"+cal.plusMonths(1).withDayOfMonth(i+1).toString("yyyy-MM-dd")+": "+": ");
}
}
sql.close();
}
public long getItemId(int position){
return position;
}
#SuppressLint("NewApi")
public View getView(int position, View convertView, ViewGroup parent){
View row = convertView;
if(row == null){
LayoutInflater inflater = (LayoutInflater) _context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
row = inflater.inflate(R.layout.calendar_day_gridcell, parent, false);
}
gridcell = (Button) row.findViewById(R.id.calendar_day_gridcell);
String[] day_color = list.get(position).split(":");
DateTime datum = DateTime.parse(day_color[1]);
if(!(day_color[0].equals("DAY"))){
gridcell.setText(String.valueOf(datum.getDayOfMonth()));
gridcell.setTag(datum.toString("yyyy-MM-dd"));
gridcell.setOnClickListener(this);
if (!day_color[2].equals(" "))
gridcell.setTextColor(Color.RED);
else if (day_color[0].equals("GREY"))
{
gridcell.setTextColor(Color.LTGRAY);
}
else if (day_color[0].equals("WHITE"))
{
gridcell.setTextColor(Color.WHITE);
}
else if (day_color[0].equals("BLUE"))
{
gridcell.setTextColor(getResources().getColor(R.color.static_text_color));
}
if(day_color[3].equals("green")){
int sdk = android.os.Build.VERSION.SDK_INT;
if(sdk < android.os.Build.VERSION_CODES.JELLY_BEAN) {
gridcell.setBackgroundDrawable(getResources().getDrawable(R.drawable.calendar_tile_green));
} else {
gridcell.setBackground(getResources().getDrawable(R.drawable.calendar_tile_green));
}
}
}
else {
gridcell.setText(datum.toString("EE"));
gridcell.setClickable(false);
}
gridcell.setOnLongClickListener(new View.OnLongClickListener() {
public boolean onLongClick(View v) {
if(gridcell.getBackground()==getResources().getDrawable(R.drawable.calendar_tile_green)){
SQLiteAdapter sql= new SQLiteAdapter(context);
DateTime bt = DateTime.parse(gridcell.getTag().toString());
sql.openToWrite(month(bt));
sql.getRows(month(bt));
sql.close();
}
return true;
}
});
return row;
}
Of course I'm accepting different solutions to provide the same smoothing scrolling.
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!
I am working on image gallery for which i have made use of ViewPager addon api. I am loading images from a specific folder in sdcard. My goal is to display only 9 images per screen in ViewPager, which i am not able to achieve. The below code is the mainactivity.
public class AndroidSwipeGalleryActivity extends Activity {
private int size;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
super.setContentView(R.layout.image_gallery);
File file = new File(Environment.getExternalStorageDirectory()+"/xxxxxxx/images");
if (file.exists()) {
size = file.listFiles().length;
System.out.println("=====File exists====Length is====="+size);
double quo = (double)size/9;
System.out.println("====Dividing by 9====" + quo);
size = (int) Math.ceil(quo);
System.out.println("===Math===== "+size);
} else {
System.out.println("======File does not exists====");
}
MyPagerAdapter adapter = new MyPagerAdapter(this);
adapter.setScrCount(size);
ViewPager myPager = (ViewPager) findViewById(R.id.viewpager);
myPager.setAdapter(adapter);
myPager.setCurrentItem(0);
}
}
The Pager Adapter and Image adapter are in the below class:
public class MyPagerAdapter extends PagerAdapter {
private TextView tv;
private GridView gv;
private int scrCount;
private int count;
public int imageCount;
private Cursor cursor;
private int columnIndex;
private Activity act;
public MyPagerAdapter(Activity act) {
this.act = act;
}
public int getCount() {
return getScrCount();
}
public Object instantiateItem(View collection, int position) {
// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Create the cursor pointing to the SDCard
String uri = MediaStore.Images.Media.DATA;
String condition = uri + " like '%/beverlyhills/images%'";
cursor = act.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, null, condition, null, null);
count = cursor.getCount();
System.out.println("Cursor count::::"+count);
// Get the column index of the Thumbnails Image ID
columnIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.Thumbnails._ID);
// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
LayoutInflater inflater = (LayoutInflater) collection.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
int resId = 0;
for (int i = 0; i < getScrCount() ; i++) {
if (count > 9) {
if (position == i) {
int num = 0;
num = count - 9;
count = num;
imageCount = 9;
}
} else {
imageCount = count;
}
}
resId = R.layout.number_one;
View view = inflater.inflate(resId, null);
((ViewPager) collection).addView(view, 0);
tv = (TextView) collection.findViewById(R.id.swipeTitleTextView);
tv.setText("Swipe Gallery");
gv = (GridView) collection.findViewById(R.id.galleryGridView);
ImageAdapter imageAdapter = new ImageAdapter(collection.getContext(), imageCount);
gv.setAdapter(imageAdapter);
// Set up a click listener
gv.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(#SuppressWarnings("rawtypes") AdapterView parent, View v, int position, long id) {
// Get the data location of the image
String[] projection = {MediaStore.Images.Media.DATA};
cursor = act.managedQuery( MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
projection, // Which columns to return
null, // Return all rows
null,
null);
columnIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToPosition(position);
// Get image filename
String imagePath = cursor.getString(columnIndex);
// Use this path to do further processing, i.e. full screen display
System.out.println("=====Image Path:::::"+imagePath);
}
});
return view;
}
#Override
public void destroyItem(View arg0, int arg1, Object arg2) {
((ViewPager) arg0).removeView((View) arg2);
}
#Override
public boolean isViewFromObject(View arg0, Object arg1) {
return arg0 == ((View) arg1);
}
#Override
public Parcelable saveState() {
return null;
}
#Override
public void finishUpdate(View arg0) {
// TODO Auto-generated method stub
}
#Override
public void restoreState(Parcelable arg0, ClassLoader arg1) {
// TODO Auto-generated method stub
}
#Override
public void startUpdate(View arg0) {
// TODO Auto-generated method stub
}
public int getScrCount() {
return scrCount;
}
public void setScrCount(int scrCount) {
this.scrCount = scrCount;
}
private class ImageAdapter extends BaseAdapter {
private int count;
public ImageAdapter(Context ctx, int count) {
this.count = count;
}
#Override
public int getCount() {
return count;
}
#Override
public Object getItem(int position) {
return position;
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ImageView picturesView;
if (convertView == null) {
picturesView = new ImageView(act);
// Move cursor to current position
cursor.moveToPosition(position);
// Get the current value for the requested column
int imageID = cursor.getInt(columnIndex);
// Set the content of the image based on the provided URI
picturesView.setImageURI(Uri.withAppendedPath(
MediaStore.Images.Thumbnails.EXTERNAL_CONTENT_URI, "" + imageID));
picturesView.setScaleType(ImageView.ScaleType.FIT_CENTER);
picturesView.setPadding(8, 8, 8, 8);
picturesView.setLayoutParams(new GridView.LayoutParams(100, 100));
}
else {
picturesView = (ImageView)convertView;
}
return picturesView;
}
}
}
The problem is I am able to load the images and display them on screen but not able to display exactly 9 images per screen. Please go through the code, it's not complex.
i have create the other demo example of view pager to manage the page and also load images. follow the steps wise, its perfectly works..
its a Pager adapter and mDataHolder(List of images) and
Set the property of gridview android:numColumns="3"
private int size;
private int start;
private int end;
private int MATRIX = 9;
public int getCount() {
int size = 0;
if (mDataHolder != null)
modular = mDataHolder.get_Listholder().size() % MATRIX;
if (modular != 0)
size++;
return ((mDataHolder.get_Listholder().size()) / MATRIX) + size;
}
#Override
public Object instantiateItem(ViewGroup container, final int pageIndex) {
mRelativeLayoutInflater = (RelativeLayout) mMasterFragmentActivity.getLayoutInflater().inflate(R.layout.member_pager_adapter, container, false);
mGridView = (GridView) mRelativeLayoutInflater.findViewById(R.id.member_gridView_list);
Calculation of pages<
size = MATRIX;
start = pageIndex * MATRIX;
end = 0;
int temp = 0;
if ((start + MATRIX) < mDataHolder.get_Listholder().size()) {
end = start + MATRIX;
} else {
temp = mDataHolder.get_Listholder().size() - start;
end = start + temp;
size = temp;
}
... and then pass the variable to gridview adapter to set other content in pager.
mAdapterMember = new AdapterMember(mContext, start, end, size);
mGridView.setAdapter(mAdapterMember);
((ViewPager) container).addView(mRelativeLayoutInflater);
return mRelativeLayoutInflater;
}
Below Manage pages variables also use the Gridview adapter to set the postion.
when the set page content position to be like (start + position)
private class AdapterMember extends BaseAdapter {
private ViewHolder mViewHolder;
private Context mContext;
private int start;
private int end;
private int size;
private AdapterMember(Context mContext, int start, int end, int size) {
this.mContext = mContext;
this.start = start;
this.end = end;
this.size = size;
}
#Override
public int getCount() {
if (size > 0)
return size;
else
return 0;
}
#Override
public Object getItem(int position) {
if (mMemberListVO.getMember().size() > 0)
return mMemberListVO.getMember().get(position);
else
return position;
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = ((Activity) mContext).getLayoutInflater().inflate(R.layout.row_member_list, null);
mViewHolder = new ViewHolder();
mViewHolder.mImageViewMemberPhoto = (NetworkImageView) convertView .findViewById(R.id.row_member_list_imageView_person);
mViewHolder.mTextViewMemberName = (TextView) convertView .findViewById(R.id.row_member_list_textview_person_name);
mViewHolder.mTextViewMemberDesignation = (TextView) convertView .findViewById(R.id.row_member_list_textview_person_designation);
mViewHolder.mTextViewMemberAddress = (TextView) convertView .findViewById(R.id.row_member_list_textview_person_address);
mViewHolder.mTextViewMemberNotification = (TextView) convertView .findViewById(R.id.row_member_list_imageview_msg_notification);
convertView.setTag(mViewHolder);
} else {
mViewHolder = (ViewHolder) convertView.getTag();
}
mViewHolder.mTextViewMemberName.setText(mDataHolder.get_Listholder().get(start + position) .get(DBHelper.mFieldMember_First_Name)
+ getString(R.string.double_quate_with_space)
+ mDataHolder.get_Listholder(). get(start + position).get(DBHelper.mFieldMember_Last_Name));
mViewHolder.mTextViewMemberDesignation.setText(mDataHolder.get_Listholder().get(start + position)
.get(DBHelper.mFieldMember_Occupation));
mViewHolder.mTextViewMemberAddress.setText(mDataHolder.get_Listholder().get(start + position) .get(DBHelper.mFieldMember_Block_No)
+ "," + getString(R.string.double_quate_with_space)
+ mDataHolder.get_Listholder().get(start + position).get(DBHelper.mFieldMember_House_No) + ","
+ getString(R.string.double_quate_with_space)
+ mDataHolder.get_Listholder().get(start + position).get(DBHelper.mFieldMember_Home_Address) + ".");
return convertView;
}
private class ViewHolder {
private NetworkImageView mImageViewMemberPhoto;
private TextView mTextViewMemberName, mTextViewMemberDesignation, mTextViewMemberAddress,
mTextViewMemberNotification;
}
}
its perfectly Working with your requirement...
The problem is solve to load the images and display them on screen its display exactly 9 images per screen.