I have an application in which I am showing ListView with two different layouts. I have about 25 items in a list and initial items shows in well order with everything as I want but when I scroll down some items in particular row overrides each other and every time I scroll they show up in different manner than the previous one. Images also gets shuffled and overrides each other.
This is my Custom Adapter class :-
public class CustomAdapterSettings extends BaseAdapter {
private static final int TYPE_ITEM = 0;
private static final int TYPE_SEPARATOR = 1;
private static final int TYPE_MAX_COUNT = TYPE_SEPARATOR + 1;
private ArrayList<String> arrListData = new ArrayList<String>();
private ArrayList<String> arrListDescription = new ArrayList<String>();
private LayoutInflater layInflater;
private Context context;
private TreeSet<Integer> treeSeparatorsSet = new TreeSet<Integer>();
public CustomAdapterSettings(Context context) {
this.context = context;
layInflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
public void addItem(final String data, final String description) {
arrListData.add(data);
arrListDescription.add(description);
notifyDataSetChanged();
}
public void addSeparatorItem(final String seperator) {
arrListData.add(seperator);
arrListDescription.add(seperator);
// save separator position
treeSeparatorsSet.add(arrListData.size() - 1);
notifyDataSetChanged();
}
#Override
public int getItemViewType(int position) {
return treeSeparatorsSet.contains(position) ? TYPE_SEPARATOR
: TYPE_ITEM;
}
#Override
public int getViewTypeCount() {
return TYPE_MAX_COUNT;
}
#Override
public int getCount() {
return arrListData.size();
}
#Override
public String getItem(int position) {
return arrListData.get(position);
}
public String getItemDescription(int position) {
return arrListDescription.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
private static class ViewHolder {
public TextView tvSettingsTagSeper;
public TextView tvSettingsDescription;
public CheckBox cbSettings;
public ImageView ivSettings;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder = null;
int type;
type = getItemViewType(position);
System.out.println("getView " + position + " " + convertView
+ " type = " + type);
if (convertView == null) {
viewHolder = new ViewHolder();
switch (type) {
case TYPE_ITEM:
convertView = layInflater.inflate(
R.layout.layout_settings_list, null);
viewHolder.tvSettingsTagSeper = (TextView) convertView
.findViewById(R.id.tvSettingsTag);
viewHolder.tvSettingsDescription = (TextView) convertView
.findViewById(R.id.tvSettingsDescription);
viewHolder.cbSettings = (CheckBox) convertView
.findViewById(R.id.cbSettings);
viewHolder.ivSettings = (ImageView) convertView
.findViewById(R.id.ivSettings);
break;
case TYPE_SEPARATOR:
convertView = layInflater.inflate(R.layout.layout_seperator,
null);
viewHolder.tvSettingsTagSeper = (TextView) convertView
.findViewById(R.id.tvSeperator);
break;
}
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
if (type == 0) {
viewHolder.tvSettingsTagSeper.setTextSize(
TypedValue.COMPLEX_UNIT_PX,
(int) (ScreenCalculationActivity.heightScreen * 0.035));
viewHolder.tvSettingsTagSeper.setPadding(0,
(int) (ScreenCalculationActivity.heightScreen * 0.01),
(int) (ScreenCalculationActivity.widthScreen * 0.15), 0);
viewHolder.tvSettingsDescription.setPadding(0,
(int) (ScreenCalculationActivity.heightScreen * 0.001),
(int) (ScreenCalculationActivity.widthScreen * 0.15), 0);
RelativeLayout.LayoutParams layParams = (RelativeLayout.LayoutParams) viewHolder.ivSettings
.getLayoutParams();
layParams.setMargins(0, 0,
(int) (ScreenCalculationActivity.widthScreen * 0.045), 0);
viewHolder.ivSettings.getLayoutParams().height = (int) (ScreenCalculationActivity.heightScreen * 0.06);
viewHolder.ivSettings.getLayoutParams().width = (int) (ScreenCalculationActivity.heightScreen * 0.06);
viewHolder.ivSettings.setLayoutParams(layParams);
layParams = (RelativeLayout.LayoutParams) viewHolder.cbSettings
.getLayoutParams();
layParams.setMargins(0, 0,
(int) (ScreenCalculationActivity.widthScreen * 0.03), 0);
viewHolder.cbSettings.setLayoutParams(layParams);
layParams = (RelativeLayout.LayoutParams) viewHolder.tvSettingsTagSeper
.getLayoutParams();
layParams.setMargins(
(int) (ScreenCalculationActivity.widthScreen * 0.05), 0, 0,
0);
viewHolder.tvSettingsTagSeper.setLayoutParams(layParams);
layParams = (RelativeLayout.LayoutParams) viewHolder.tvSettingsDescription
.getLayoutParams();
layParams.setMargins(
(int) (ScreenCalculationActivity.widthScreen * 0.05), 0, 0,
0);
viewHolder.tvSettingsDescription.setLayoutParams(layParams);
} else {
RelativeLayout.LayoutParams layParams = (RelativeLayout.LayoutParams) viewHolder.tvSettingsTagSeper
.getLayoutParams();
layParams.setMargins(
(int) (ScreenCalculationActivity.widthScreen * 0.02), 0, 0,
0);
viewHolder.tvSettingsTagSeper.setLayoutParams(layParams);
}
if (type == 0) {
if (position == 1 || position == 2 || position == 3
|| position == 6 || position == 9 || position == 10
|| position == 12 || position == 14 || position == 16
|| position == 18 || position == 22) {
viewHolder.ivSettings.setVisibility(View.VISIBLE);
} else {
viewHolder.cbSettings.setVisibility(View.VISIBLE);
}
viewHolder.cbSettings.setFocusable(false);
viewHolder.cbSettings.setFocusableInTouchMode(false);
viewHolder.ivSettings.setFocusable(false);
viewHolder.ivSettings.setFocusableInTouchMode(false);
if (arrListDescription.get(position) == null) {
RelativeLayout.LayoutParams layParams = (RelativeLayout.LayoutParams) viewHolder.tvSettingsTagSeper
.getLayoutParams();
layParams.addRule(RelativeLayout.CENTER_VERTICAL);
viewHolder.tvSettingsTagSeper.setLayoutParams(layParams);
}
viewHolder.tvSettingsTagSeper.setText(arrListData.get(position));
viewHolder.tvSettingsDescription.setText(arrListDescription
.get(position));
} else {
viewHolder.tvSettingsTagSeper.setText(arrListData.get(position));
}
return convertView;
}
}
This is my layout layout_settings_list :-
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/relLaySettings"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:id="#+id/tvSettingsTag"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scrollHorizontally="true"
android:singleLine="true"
android:textColor="#color/White"
android:textStyle="bold"
android:typeface="monospace" />
<TextView
android:id="#+id/tvSettingsDescription"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/tvSettingsTag"
android:textColor="#color/LightGrey" />
<CheckBox
android:id="#+id/cbSettings"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:visibility="gone" />
<ImageView
android:id="#+id/ivSettings"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:adjustViewBounds="true"
android:scaleType="fitCenter"
android:src="#drawable/dropdown2"
android:visibility="gone" />
This is my layout layout_seperator :-
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#color/LightGrey"
android:clickable="false">
<TextView
android:id="#+id/tvSeperator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:textStyle="bold"
android:textColor="#color/Black" />
I don't see the exact source of your problem, but I see several little issues that might cause what you see.
Several backing lists
The purpose of your adapter is to convert a list of objects into a list a views in the screen. Having multiple lists containing the data does not seem right to me. It shouldn't cause actual problems, but it could make your mental representation harder.
You should probably have objects encapsulating the properties you will reflect in your views:
public class Item {
}
public class DataItem extends Item {
String data;
String description;
}
public class SeparatorItem extends Item {
String description;
}
And instead of 2 lists and 1 set, you would only have one list:
ArrayList<Item> list;
Then you could base your item type on the actual class of the item (instead of using a Set of indices):
#Override
public int getItemViewType(int position) {
Item item = list.get(position);
if (item instanceof DataItem)
return TYPE_ITEM;
else
return TYPE_SEPARATOR;
}
Suspicious if statement
if (position == 1 || position == 2 || position == 3
|| position == 6 || position == 9 || position == 10
|| position == 12 || position == 14 || position == 16
|| position == 18 || position == 22) {
viewHolder.ivSettings.setVisibility(View.VISIBLE);
} else {
viewHolder.cbSettings.setVisibility(View.VISIBLE);
}
Two problems with this if:
it hardcodes some positions. There should be a field in your backing objects (the Items of your list) that represents the fact that ivSettings or cbSettings (one view or the other) should be displayed.
you use setVisibility(View.VISIBLE), but where do you set the other view to View.GONE? They are not initialized, so the visibility of ivSettings or cbSettings (the one you don't make visible) will be the one of your convertView.
Suggested corrected if:
Item item = list.get(position);
if (item.shouldDisplayIvSettings()) {
viewHolder.ivSettings.setVisibility(View.VISIBLE);
viewHolder.cbSettings.setVisibility(View.GONE);
} else {
viewHolder.ivSettings.setVisibility(View.GONE);
viewHolder.cbSettings.setVisibility(View.VISIBLE);
}
Constants declarations VS use of integer literals
You had it right when you declared constants for your types of elements:
private static final int TYPE_ITEM = 0;
private static final int TYPE_SEPARATOR = 1;
But then you don't use the constants, but integer literals in your ifs:
if (type == 0) {
This is not much, but could cause errors when your code evolves. It should be replaced by the appropriate constant:
if (type == TYPE_ITEM) {
Related
I attempted to reverse engineer a gridview from an example found here:
https://github.com/liaohuqiu/android-GridViewWithHeaderAndFooter
using his source code found here:
https://github.com/liaohuqiu/android-cube-app/blob/master/src/in/srain/cube/demo/ui/fragment/GridViewWithHeaderAndFooterFragment.java#L89
but keep getting a casting error when I try to display images within it.
I would like to learn how to do it myself because his code crashes when I try loading images using glide.
Here is the gridview code I have:
package customgridapp.customgridview;
import android.annotation.SuppressLint;
import android.content.Context;
import android.database.DataSetObservable;
import android.database.DataSetObserver;
import android.os.Build;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.FrameLayout;
import android.widget.GridView;
import android.widget.ListAdapter;
import android.widget.WrapperListAdapter;
import java.util.ArrayList;
public class TestFooterGridView extends GridView{
private static final String TAG = "TestFooterGridView";
/**
* A class that represents a fixed view in a list, for example a header at the top
* or a footer at the bottom.
*/
private static class FixedViewInfo {
/**
* The view to add to the grid
*/
public View view;
public ViewGroup viewContainer;
/**
* The data backing the view. This is returned from {#link ListAdapter#getItem(int)}.
*/
public Object data;
/**
* <code>true</code> if the fixed view should be selectable in the grid
*/
public boolean isSelectable;
}
private ArrayList<FixedViewInfo> mHeaderViewInfos = new ArrayList<FixedViewInfo>();
private ArrayList<FixedViewInfo> mFooterViewInfos = new ArrayList<FixedViewInfo>();
private int mRequestedNumColumns;
private int mNumColmuns = 1;
private void initHeaderGridView() {
super.setClipChildren(false);
}
public TestFooterGridView(Context context) {
super(context);
initHeaderGridView();
}
public TestFooterGridView(Context context, AttributeSet attrs) {
super(context, attrs);
initHeaderGridView();
}
public TestFooterGridView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initHeaderGridView();
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (mRequestedNumColumns != AUTO_FIT) {
mNumColmuns = mRequestedNumColumns;
}
if (mNumColmuns <= 0) {
mNumColmuns = 1;
}
ListAdapter adapter = getAdapter();
if (adapter != null && adapter instanceof FooterViewGridAdapter) {
((FooterViewGridAdapter) adapter).setNumColumns(getNumColumns());
}
}
#Override
public void setClipChildren(boolean clipChildren) {
// Ignore, since the header rows depend on not being clipped
}
/**
* Add a fixed view to appear at the top of the grid. If addHeaderView is
* called more than once, the views will appear in the order they were
* added. Views added using this call can take focus if they want.
* <p>
* NOTE: Call this before calling setAdapter. This is so HeaderFooterGridView can wrap
* the supplied cursor with one that will also account for header views.
*
* #param v The view to add.
* #param data Data to associate with this view
* #param isSelectable whether the item is selectable
*/
public void addHeaderView(View v, Object data, boolean isSelectable) {
ListAdapter adapter = getAdapter();
if (adapter != null && !(adapter instanceof FooterViewGridAdapter)) {
throw new IllegalStateException(
"Cannot add header view to grid -- setAdapter has already been called.");
}
FixedViewInfo info = new FixedViewInfo();
// FrameLayout fl = new FullWidthFixedViewLayout(getContext());
// fl.addView(v);
info.view = v;
// info.viewContainer = fl;
info.data = data;
info.isSelectable = isSelectable;
mHeaderViewInfos.add(info);
// in the case of re-adding a header view, or adding one later on,
// we need to notify the observer
if (adapter != null) {
((FooterViewGridAdapter) adapter).notifyDataSetChanged();
}
}
/**
* Add a fixed view to appear at the bottom of the grid. If addFooterView is
* called more than once, the views will appear in the order they were
* added. Views added using this call can take focus if they want.
* <p>
* NOTE: Call this before calling setAdapter. This is so HeaderFooterGridView can wrap
* the supplied cursor with one that will also account for header views.
*
* #param v The view to add.
* #param data Data to associate with this view
* #param isSelectable whether the item is selectable
*/
public void addFooterView(View v, Object data, boolean isSelectable) {
ListAdapter adapter = getAdapter();
if (adapter != null && !(adapter instanceof FooterViewGridAdapter)) {
throw new IllegalStateException(
"Cannot add footer view to grid -- setAdapter has already been called.");
}
FixedViewInfo info = new FixedViewInfo();
FrameLayout fl = new FullWidthFixedViewLayout(getContext());
fl.addView(v);
info.view = v;
info.viewContainer = fl;
info.data = data;
info.isSelectable = isSelectable;
mFooterViewInfos.add(info);
// in the case of re-adding a header view, or adding one later on,
// we need to notify the observer
if (adapter != null) {
((FooterViewGridAdapter) adapter).notifyDataSetChanged();
}
}
/**
* Add a fixed view to appear at the bottom of the grid. If addFooterView is
* called more than once, the views will appear in the order they were
* added. Views added using this call can take focus if they want.
* <p>
* NOTE: Call this before calling setAdapter. This is so HeaderFooterGridView can wrap
* the supplied cursor with one that will also account for header views.
*
* #param v The view to add.
*/
public void addFooterView(View v) {
addFooterView(v, null, false);
}
private void removeFixedViewInfo(View v, ArrayList<FixedViewInfo> where) {
int len = where.size();
for (int i = 0; i < len; ++i) {
FixedViewInfo info = where.get(i);
if (info.view == v) {
where.remove(i);
break;
}
}
}
#Override
public void setAdapter(ListAdapter adapter) {
if (mHeaderViewInfos.size() > 0 || mFooterViewInfos.size() > 0) {
FooterViewGridAdapter hadapter = new FooterViewGridAdapter(mFooterViewInfos, adapter);
int numColumns = getNumColumns();
if (numColumns > 1) {
hadapter.setNumColumns(numColumns);
}
super.setAdapter(hadapter);
} else {
super.setAdapter(adapter);
}
}
private class FullWidthFixedViewLayout extends FrameLayout {
public FullWidthFixedViewLayout(Context context) {
super(context);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int targetWidth = TestFooterGridView.this.getMeasuredWidth()
- TestFooterGridView.this.getPaddingLeft()
- TestFooterGridView.this.getPaddingRight();
widthMeasureSpec = MeasureSpec.makeMeasureSpec(targetWidth,
MeasureSpec.getMode(widthMeasureSpec));
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
#Override
public void setNumColumns(int numColumns) {
super.setNumColumns(numColumns);
// Store specified value for less than Honeycomb.
mRequestedNumColumns = numColumns;
}
#Override
#SuppressLint("NewApi")
public int getNumColumns() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
return super.getNumColumns();
}
// Return value for less than Honeycomb.
return mNumColmuns;
}
/**
* ListAdapter used when a HeaderFooterGridView has header views. This ListAdapter
* wraps another one and also keeps track of the header views and their
* associated data objects.
* <p>This is intended as a base class; you will probably not need to
* use this class directly in your own code.
*/
private static class FooterViewGridAdapter implements WrapperListAdapter, Filterable {
// This is used to notify the container of updates relating to number of columns
// or headers changing, which changes the number of placeholders needed
private final DataSetObservable mDataSetObservable = new DataSetObservable();
private final ListAdapter mAdapter;
private int mNumColumns = 1;
// This ArrayList is assumed to NOT be null.
ArrayList<FixedViewInfo> mFooterViewInfos;
boolean mAreAllFixedViewsSelectable;
private final boolean mIsFilterable;
public FooterViewGridAdapter(ArrayList<FixedViewInfo> footerViewInfos, ListAdapter adapter) {
mAdapter = adapter;
mIsFilterable = adapter instanceof Filterable;
if (footerViewInfos == null) {
throw new IllegalArgumentException("footerViewInfos cannot be null");
}
mFooterViewInfos = footerViewInfos;
mAreAllFixedViewsSelectable = areAllListInfosSelectable(mFooterViewInfos);
}
public int getHeadersCount() {
return 0;
}
public int getFootersCount() {
return mFooterViewInfos.size();
}
#Override
public boolean isEmpty() {
return (mAdapter == null || mAdapter.isEmpty()) && getHeadersCount() == 0 && getFootersCount() == 0;
}
public void setNumColumns(int numColumns) {
if (numColumns < 1) {
throw new IllegalArgumentException("Number of columns must be 1 or more");
}
if (mNumColumns != numColumns) {
mNumColumns = numColumns;
notifyDataSetChanged();
}
}
private boolean areAllListInfosSelectable(ArrayList<FixedViewInfo> infos) {
if (infos != null) {
for (FixedViewInfo info : infos) {
if (!info.isSelectable) {
return false;
}
}
}
return true;
}
public boolean removeFooter(View v) {
for (int i = 0; i < mFooterViewInfos.size(); i++) {
FixedViewInfo info = mFooterViewInfos.get(i);
if (info.view == v) {
mFooterViewInfos.remove(i);
mAreAllFixedViewsSelectable = areAllListInfosSelectable(mFooterViewInfos);
mDataSetObservable.notifyChanged();
return true;
}
}
return false;
}
#Override
public int getCount() {
if (mAdapter != null) {
final int lastRowItemCount = (mAdapter.getCount() % mNumColumns);
final int emptyItemCount = ((lastRowItemCount == 0) ? 0 : mNumColumns - lastRowItemCount);
return (getHeadersCount() * mNumColumns) + mAdapter.getCount() + emptyItemCount + (getFootersCount() * mNumColumns);
} else {
return (getHeadersCount() * mNumColumns) + (getFootersCount() * mNumColumns);
}
}
#Override
public boolean areAllItemsEnabled() {
if (mAdapter != null) {
return mAreAllFixedViewsSelectable && mAdapter.areAllItemsEnabled();
} else {
return true;
}
}
#Override
public boolean isEnabled(int position) {
// Header (negative positions will throw an ArrayIndexOutOfBoundsException)
int numHeadersAndPlaceholders = getHeadersCount() * mNumColumns;
if (position < numHeadersAndPlaceholders) {
return (position % mNumColumns == 0);
// && mHeaderViewInfos.get(position / mNumColumns).isSelectable;
}
// Adapter
if (position < numHeadersAndPlaceholders + mAdapter.getCount()) {
final int adjPosition = position - numHeadersAndPlaceholders;
int adapterCount = 0;
if (mAdapter != null) {
adapterCount = mAdapter.getCount();
if (adjPosition < adapterCount) {
return mAdapter.isEnabled(adjPosition);
}
}
}
// Empty item
final int lastRowItemCount = (mAdapter.getCount() % mNumColumns);
final int emptyItemCount = ((lastRowItemCount == 0) ? 0 : mNumColumns - lastRowItemCount);
if (position < numHeadersAndPlaceholders + mAdapter.getCount() + emptyItemCount) {
// return false;
return (position % mNumColumns == 0)
&& mFooterViewInfos.get((position - numHeadersAndPlaceholders - mAdapter.getCount() - emptyItemCount) / mNumColumns).isSelectable;
}
// Footer
int numFootersAndPlaceholders = getFootersCount() * mNumColumns;
if (position < numHeadersAndPlaceholders + mAdapter.getCount() + emptyItemCount + numFootersAndPlaceholders) {
return (position % mNumColumns == 0)
&& mFooterViewInfos.get((position - numHeadersAndPlaceholders - mAdapter.getCount() - emptyItemCount) / mNumColumns).isSelectable;
}
throw new ArrayIndexOutOfBoundsException(position);
}
#Override
public Object getItem(int position) {
// Header (negative positions will throw an ArrayIndexOutOfBoundsException)
int numHeadersAndPlaceholders = getHeadersCount() * mNumColumns;
if (position < numHeadersAndPlaceholders) {
if (position % mNumColumns == 0) {
return 0; //mHeaderViewInfos.get(position / mNumColumns).data;
}
return null;
}
// Adapter
if (position < numHeadersAndPlaceholders + mAdapter.getCount()) {
final int adjPosition = position - numHeadersAndPlaceholders;
int adapterCount = 0;
if (mAdapter != null) {
adapterCount = mAdapter.getCount();
if (adjPosition < adapterCount) {
return mAdapter.getItem(adjPosition);
}
}
}
// Empty item
final int lastRowItemCount = (mAdapter.getCount() % mNumColumns);
Log.e(TAG, "Lastrowitemcount:" + lastRowItemCount);
final int emptyItemCount = ((lastRowItemCount == 0) ? 0 : mNumColumns - lastRowItemCount);
Log.e(TAG, "emptyitemcount:" + emptyItemCount);
if (position < numHeadersAndPlaceholders + mAdapter.getCount() + emptyItemCount) {
/*return null;*/
return mFooterViewInfos.get((position - numHeadersAndPlaceholders - mAdapter.getCount() - emptyItemCount) / mNumColumns).data;
}
// Footer
int numFootersAndPlaceholders = getFootersCount() * mNumColumns;
if (position < numHeadersAndPlaceholders + mAdapter.getCount() + emptyItemCount + numFootersAndPlaceholders) {
if (position % mNumColumns == 0) {
return mFooterViewInfos.get((position - numHeadersAndPlaceholders - mAdapter.getCount() - emptyItemCount) / mNumColumns).data;
}
}
throw new ArrayIndexOutOfBoundsException(position);
}
#Override
public long getItemId(int position) {
int numHeadersAndPlaceholders = getHeadersCount() * mNumColumns;
if (mAdapter != null) {
if (position >= numHeadersAndPlaceholders && position < numHeadersAndPlaceholders + mAdapter.getCount()) {
int adjPosition = position - numHeadersAndPlaceholders;
int adapterCount = mAdapter.getCount();
if (adjPosition < adapterCount) {
return mAdapter.getItemId(adjPosition);
}
}
}
return -1;
}
#Override
public boolean hasStableIds() {
if (mAdapter != null) {
return mAdapter.hasStableIds();
}
return false;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// Header (negative positions will throw an ArrayIndexOutOfBoundsException)
int numHeadersAndPlaceholders = getHeadersCount() * mNumColumns;
if (position < numHeadersAndPlaceholders) {
/*View headerViewContainer = mHeaderViewInfos
.get(position / mNumColumns).viewContainer;*/
if (position % mNumColumns == 0) {
return null; //headerViewContainer;
} else {
convertView = new View(parent.getContext());
// We need to do this because GridView uses the height of the last item
// in a row to determine the height for the entire row.
convertView.setVisibility(View.INVISIBLE);
// convertView.setMinimumHeight(headerViewContainer.getHeight());
return convertView;
}
}
// Adapter
// TODO Current implementation may not be enough in the case of 3 or more column. May need to be careful on the INVISIBLE View height.
if (position < numHeadersAndPlaceholders + mAdapter.getCount()) {
final int adjPosition = position - numHeadersAndPlaceholders;
int adapterCount = 0;
if (mAdapter != null) {
adapterCount = mAdapter.getCount();
if (adjPosition < adapterCount) {
convertView = mAdapter.getView(adjPosition, convertView, parent);
convertView.setVisibility(View.VISIBLE);
return convertView;
}
}
}
// Empty item
final int lastRowItemCount = (mAdapter.getCount() % mNumColumns);
Log.e(TAG, "Lastrowitemcount:" + lastRowItemCount);
final int emptyItemCount = ((lastRowItemCount == 0) ? 0 : mNumColumns - lastRowItemCount);
Log.e(TAG, "Emptyitemcount:" + emptyItemCount);
if (position < numHeadersAndPlaceholders + mAdapter.getCount() + emptyItemCount) {
// We need to do this because GridView uses the height of the last item
// in a row to determine the height for the entire row.
// TODO Current implementation may not be enough in the case of 3 or more column. May need to be careful on the INVISIBLE View height.
convertView = mAdapter.getView(mAdapter.getCount() - 1, convertView, parent);
convertView.setVisibility(View.INVISIBLE);
return convertView;
}
// Footer
int numFootersAndPlaceholders = getFootersCount() * mNumColumns;
if (position < numHeadersAndPlaceholders + mAdapter.getCount() + emptyItemCount + numFootersAndPlaceholders) {
View footerViewContainer = mFooterViewInfos
.get((position - numHeadersAndPlaceholders - mAdapter.getCount() - emptyItemCount) / mNumColumns).viewContainer;
if (position % mNumColumns == 0) {
return footerViewContainer;
} else {
convertView = new View(parent.getContext());
// We need to do this because GridView uses the height of the last item
// in a row to determine the height for the entire row.
convertView.setVisibility(View.INVISIBLE);
convertView.setMinimumHeight(footerViewContainer.getHeight());
return convertView;
}
}
throw new ArrayIndexOutOfBoundsException(position);
}
#Override
public int getItemViewType(int position) {
int numHeadersAndPlaceholders = getHeadersCount() * mNumColumns;
if (position < numHeadersAndPlaceholders && (position % mNumColumns != 0)) {
// Placeholders get the last view type number
return mAdapter != null ? mAdapter.getViewTypeCount() : 1;
}
if (mAdapter != null && position >= numHeadersAndPlaceholders && position < numHeadersAndPlaceholders + mAdapter.getCount() + (mNumColumns - (mAdapter.getCount() % mNumColumns))) {
int adjPosition = position - numHeadersAndPlaceholders;
int adapterCount = mAdapter.getCount();
if (adjPosition < adapterCount) {
return mAdapter.getItemViewType(adjPosition);
} else if (adapterCount != 0 && mNumColumns != 1) {
return mAdapter.getItemViewType(adapterCount - 1);
}
}
int numFootersAndPlaceholders = getFootersCount() * mNumColumns;
if (mAdapter != null && position < numHeadersAndPlaceholders + mAdapter.getCount() + numFootersAndPlaceholders) {
return mAdapter != null ? mAdapter.getViewTypeCount() : 1;
}
return AdapterView.ITEM_VIEW_TYPE_HEADER_OR_FOOTER;
}
#Override
public int getViewTypeCount() {
if (mAdapter != null) {
return mAdapter.getViewTypeCount() + 1;
}
return 2;
}
#Override
public void registerDataSetObserver(DataSetObserver observer) {
mDataSetObservable.registerObserver(observer);
if (mAdapter != null) {
mAdapter.registerDataSetObserver(observer);
}
}
#Override
public void unregisterDataSetObserver(DataSetObserver observer) {
mDataSetObservable.unregisterObserver(observer);
if (mAdapter != null) {
mAdapter.unregisterDataSetObserver(observer);
}
}
#Override
public Filter getFilter() {
if (mIsFilterable) {
return ((Filterable) mAdapter).getFilter();
}
return null;
}
#Override
public ListAdapter getWrappedAdapter() {
return mAdapter;
}
public void notifyDataSetChanged() {
mDataSetObservable.notifyChanged();
}
}
}
I tried understanding his code by removing any code relating to headers and only looking at what he does with footers.
In short: How do I add a footer to a three column gridview?
What do I need?
You don't need any libraries for that. Just try this ....
Create Layout like this.....
<?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">
<android.support.v4.widget.NestedScrollView
android:id="#+id/nestedScrollView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:overScrollMode="never">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="#+id/header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="20dp"
android:text="Header"
android:textColor="#color/white"
android:textSize="16sp" />
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/footer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="20dp"
android:text="Footer"
android:textColor="#color/white"
android:textSize="16sp" />
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
</LinearLayout>
And Use this code in your Activity or Fragment...
RecyclerView recyclerView = findViewById(R.id.recyclerView);
ViewCompat.setNestedScrollingEnabled(recyclerView, false);
GridLayoutManager mLayoutManager = new GridLayoutManager(activity, 3);
recyclerView.setLayoutManager(mLayoutManager);
adapter = new YourCustomAdapter(this);
recyclerView.setAdapter(adapter);
Note:- In My point of view don't depend on libraries. If they will remove it in future then you have to change your work again. If you want to use library try to import their GitHub whole module in your project. So you don't depend on their changes. There is an incident with me, where i used image compression library in my app. After one year they removed their library and i had to work again on that module. And if your are using some famous company libraries then it is fine like Facebook, Google , Square or more. Many big company also depend on their Library.
i have created a circular recyclerview by making adapter count into Integer.MAX.Now, i need to highlight the center recycler item like in the image.Kindly help me!!
By using center indicator(textview) in the layout and addOnScrollListner we can achieve this
please refer the following example
In xml:
<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"
>
<TextView
android:layout_width="wrap_content"
android:text="↓"
android:id="#+id/centerIndicator"
android:textSize="24sp"
android:textStyle="bold"
android:visibility="visible"
android:textColor="#color/theme_yellow"
android:layout_centerHorizontal="true"
android:layout_height="wrap_content"
android:layout_marginTop="27dp"
android:background="#android:color/transparent"
/>
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:id="#+id/list"
android:clipToPadding="false"
android:divider="#android:color/transparent"
android:layout_height="wrap_content"/>
</RelativeLayout>
In Activity/Fragment:
public class Sample extends Fragment {
RecyclerView listView;
ArrayList<String>mWeekDaysList=new ArrayList<>();
LinearLayoutManager mlinearLayoutManagerForDateList;
DateAdapter mDateAdapter;
TimeListAdapter mtimeAdapter;
private int mCenterPivot;
private boolean mAutoSet = true;
Activity mactivity;
public NigaichiNiralFrag() {
// Required empty public constructor
}
#Override
public View onCreateView(final LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view= inflater.inflate(R.layout.fragment_nigaichi_niral, container, false);
mactivity=getActivity();
mWeekDaysList.add("Sunday");
mWeekDaysList.add("Monday");
mWeekDaysList.add("Tuesday");
mWeekDaysList.add("Wednesday");
mWeekDaysList.add("Thursday");
mWeekDaysList.add("Friday");
mWeekDaysList.add("Saturday");
listView = (RecyclerView) view.findViewById(R.id.list);
mlinearLayoutManagerForDateList = new LinearLayoutManager(mactivity);
mlinearLayoutManagerForDateList.setOrientation(LinearLayoutManager.HORIZONTAL);
listView.setLayoutManager(mlinearLayoutManagerForDateList);
final TextView mCenterIndicator = (TextView) view.findViewById(R.id.centerIndicator);
final int itemWidth = (int) getResources().getDimension(R.dimen.flexible_space_image_height) ;
mlinearLayoutManagerForDateList.scrollToPosition(Integer.MAX_VALUE / 2);
mDateAdapter=new DateAdapter(mWeekDaysList);
listView.setAdapter(mDateAdapter);
mCenterIndicator.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
int center = ( mCenterIndicator.getLeft() + mCenterIndicator.getRight() ) / 2 ;
int padding = center - itemWidth / 2; //Assuming both left and right padding needed are the same
listView.setPadding(5,0,5,0);
mCenterPivot = center;
listView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
LinearLayoutManager lm = (LinearLayoutManager) recyclerView.getLayoutManager();
if( mCenterPivot == 0 ) {
// Default pivot , Its a bit inaccurate .
// Better pass the center pivot as your Center Indicator view's
// calculated center on it OnGlobalLayoutListener event
mCenterPivot = lm.getOrientation() == LinearLayoutManager.HORIZONTAL ? ( recyclerView.getLeft() + recyclerView.getRight() ) : ( recyclerView.getTop() + recyclerView.getBottom() );
}
if( !mAutoSet ) {
if( newState == RecyclerView.SCROLL_STATE_IDLE ) {
//ScrollStoppped
View view = findCenterView(lm);//get the view nearest to center
//view.setBackgroundColor(Color.RED);
int position = recyclerView.getChildAdapterPosition(view) % mWeekDaysList.size();
Log.d("isideScroll",mWeekDaysList.get(position));
mDateAdapter.setSelecteditem(position);
int viewCenter = lm.getOrientation() == LinearLayoutManager.HORIZONTAL ? ( view.getLeft() + view.getRight() )/2 :( view.getTop() + view.getBottom() )/2;
//compute scroll from center
int scrollNeeded = viewCenter - mCenterPivot; // Add or subtract any offsets you need here
if( lm.getOrientation() == LinearLayoutManager.HORIZONTAL ) {
recyclerView.smoothScrollBy(scrollNeeded, 0);
}
else
{
recyclerView.smoothScrollBy(0, (int) (scrollNeeded));
}
mAutoSet =true;
}
}
if( newState == RecyclerView.SCROLL_STATE_DRAGGING || newState == RecyclerView.SCROLL_STATE_SETTLING ){
mAutoSet =false;
}
}
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
}
});
}
});
return returnView;
}
private void scrollToCenter(View v) {
int itemToScroll = listView.getChildAdapterPosition(v);
int centerOfScreen = listView.getWidth() / 2 - v.getWidth() / 2;
//v.setBackgroundColor(Color.RED);
mlinearLayoutManagerForDateList.scrollToPositionWithOffset(itemToScroll, centerOfScreen);
}
private View findCenterView(LinearLayoutManager lm) {
int minDistance = 0;
View view = null;
View returnView = null;
boolean notFound = true;
for(int i = lm.findFirstVisibleItemPosition(); i <= lm.findLastVisibleItemPosition() && notFound ; i++ ) {
view=lm.findViewByPosition(i);
int center = lm.getOrientation() == LinearLayoutManager.HORIZONTAL ? ( view.getLeft() + view.getRight() )/ 2 : ( view.getTop() + view.getBottom() )/ 2;
int leastDifference = Math.abs(mCenterPivot - center);
if( leastDifference <= minDistance || i == lm.findFirstVisibleItemPosition())
{
minDistance = leastDifference;
returnView=view;
}
else
{
notFound=false;
}
}
return returnView;
}
}
Adapter:
public class DateAdapter extends RecyclerView.Adapter<DateAdapter.ReviewHolder> {
ArrayList<String> mData;
private int selectedItem = -1;
int pos=0;
public DateAdapter(ArrayList<String> data){
mData=data;
}
#Override
public ReviewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Context context = parent.getContext();
View v= LayoutInflater.from(context).inflate(R.layout.item_horz,parent,false);
return new DateAdapter.ReviewHolder(v);
}
#Override
public void onBindViewHolder(ReviewHolder holder, int position) {
pos=position;
position = position % mData.size();
holder.tvName.setText(mData.get(position));
holder.tvName.setGravity(Gravity.CENTER);
if (position == selectedItem) {
Log.d("CenterPosition", "center" + position);
holder.tvName.setTextColor(Color.RED);
holder.tvName.setTextSize(20);
holder.tvName.setBackgroundColor(Color.parseColor("#fccd00"));
} else {
holder.tvName.setTextColor(Color.WHITE);
holder.tvName.setTextSize(16);
holder.tvName.setBackgroundColor(Color.BLACK);
}
}
#Override
public int getItemCount() {
// return mData.size();
return Integer.MAX_VALUE;
}
public class ReviewHolder extends RecyclerView.ViewHolder {
protected TextView tvName;
View container;
public ReviewHolder(View itemView) {
super(itemView);
container=itemView;
tvName= (TextView) itemView.findViewById(R.id.text);
}
}
public void setSelecteditem(int selecteditem) {
Log.d("POSITION",String.valueOf(selecteditem));
this.selectedItem = selecteditem;
notifyDataSetChanged();
}
}
item_horz.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="151dp"
android:id="#+id/wrapper"
android:background="#color/white"
android:orientation="horizontal"
android:layout_height="50dp">
<LinearLayout
android:layout_width="150dp"
android:layout_height="50dp"
android:background="#color/black">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textSize="20sp"
android:id="#+id/text"
android:textColor="#color/white"
android:text="21"
android:gravity="center"
/>
</LinearLayout>
</LinearLayout>
Hope this will help you guys..
if you want to use horizontalscrollview (create items dynamically)instead recyclerview.
create your parent layout
<HorizontalScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true">
<LinearLayout
android:layout_alignParentBottom="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"/>
</HorizontalScrollView>
inflate your childs items to parent layout.
LayoutInflater inflater = (LayoutInflater) getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
for (int i = 0; i < list.size(); i++) {
// inflate child element
final LinearLayout titleRow = (LinearLayout) inflater.inflate(R.layout.item_gallery, fragmentGalleryScrollLl, false);
final CircleImageView shapeImageView = (CircleImageView) titleRow.findViewById(R.id.item_gallery_iv);
shapeImageView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
scrollItem(titleRow);
}
});
fragmentGalleryScrollLl.addView(titleRow);
}
use this method when your click the items.
private void scrollItem(LinearLayout titleRow) {
int scrollX = (titleRow.getLeft() - (fragmentGalleryScrollSv.getWidth() / 2)) + (titleRow.getWidth() / 2);
fragmentGalleryScrollSv.smoothScrollTo(scrollX, 0);
}
Inside BindView, you can check middle position of the adapter and apply logic for image for that specific holder.
onBindViewHolder(View holder, int postion){
if(position == getItemCount() / 2)
{ //Write image logic for holder
}}
Callback to get center item position when scrolling stopped
import android.content.Context
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
class RecyclerCenterItemFinder(
private val context: Context,
private val layoutManager: LinearLayoutManager,
private val callback: (Int) -> Unit,
private val controlState: Int = RecyclerView.SCROLL_STATE_IDLE
) :
RecyclerView.OnScrollListener() {
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
if (controlState == ALL_STATES || newState == controlState) {
val firstVisible = layoutManager.findFirstVisibleItemPosition()
val lastVisible = layoutManager.findLastVisibleItemPosition()
val itemsCount = lastVisible - firstVisible + 1
val screenCenter: Int = context.resources.displayMetrics.widthPixels / 2
var minCenterOffset = Int.MAX_VALUE
var middleItemIndex = 0
for (index in 0 until itemsCount) {
val listItem = layoutManager.getChildAt(index) ?: return
val topOffset = listItem.top
val bottomOffset = listItem.bottom
val centerOffset =
Math.abs(topOffset - screenCenter) + Math.abs(bottomOffset - screenCenter)
if (minCenterOffset > centerOffset) {
minCenterOffset = centerOffset
middleItemIndex = index + firstVisible
}
}
callback(middleItemIndex)
}
}
companion object {
const val ALL_STATES = 10
}
}
recycler.addOnScrollListener(RecyclerCenterItemFinder(requireContext(),
recycler.layoutManager,
{ centerItemPosition ->
// do something
}
))
I'm using GridView for my crossword puzzle. And after scrolling the gridview messed up, all the black parts (non leter box) showing letters which not suppose to happen.
Here is my adapter. Can anyone help? Thanks
private class CrossWordPuzzleAdapter extends BaseAdapter {
private Context mContext;
private int mWidth, mHeight;
public CrossWordPuzzleAdapter(Context c, int width, int height) {
mContext = c;
mWidth = width;
mHeight = height;
}
public int getCount() {
return mWidth * mHeight;
}
public Object getItem(int position) {
return null;
}
public long getItemId(int position) {
return 0;
}
// create a new ImageView for each item referenced by the Adapter
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
LayoutInflater mInflater = (LayoutInflater) mContext
.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
if (convertView == null) {
convertView = mInflater.inflate(R.layout.box_layout, null);
holder = new ViewHolder();
holder.numberText = (TextView) convertView.findViewById(R.id.numberText);
holder.charText = (GridViewItem) convertView.findViewById(R.id.charText);
convertView.setTag(holder);
} else
holder = (ViewHolder) convertView.getTag();
int x = -1, y = -1;
if (position < mWidth) {
x = position;
y = 0;
} else {
x = position % mWidth;
y = position / mHeight;
}
if (mPuzzleBoard.getCharPlace(x, y) != '\0' && mPuzzleBoard.getCharPlace(x, y) != ' ') {
String questionNoStr = mPuzzleBoard.getQuestionNo(x, y);
holder.numberText.setText(questionNoStr);
if (isRevealed) {
holder.charText.setText("" + Character.toString(mPuzzleBoard.getCharPlace(x, y)).toUpperCase());
holder.charText.setTextColor(Color.GREEN);
}
holder.charText.setBackground(getResources().getDrawable(R.drawable.letter_box_white));
} else {
holder.charText.setBackground(getResources().getDrawable(R.drawable.letter_box_black));
convertView.setSelected(false);
}
return convertView;
}
I finally found the solution. The error box showing letters are actually previous boxes of Views that contains letters previously. So, after scrolling the position are all messed up, and even though I have set the box colour to black, but I didn't set the box to be empty.
so this is what I do:
else {
holder.numberText.setText(""); //<< reset the box to empty
holder.charText.setText(""); //<< reset the box to empty
holder.charText.setBackground(getResources().getDrawable(R.drawable.letter_box_black));
convertView.setSelected(false);
}
I create gridview with sectionviews and have some problems with it
#Override
public View getView(int position, View convertView, ViewGroup parent) {
int size = mArray.get(0).size();
int z = size + (COLUMNS_NUM * 2);
//sectionView
if (position < (COLUMNS_NUM * 2) || (position > (z -1) && position < (z + COLUMNS_NUM))) {
if(position == COLUMNS_NUM ){
return header(R.string.grid_last_added, convertView);
}
if(position == z){
return header(R.string.grid_last_added, convertView);
}
if (convertView == null) {
convertView = new View(mContext);
}
// Set empty view with height of ActionBar
convertView.setLayoutParams(new AbsListView.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, mActionBarHeight));
if(position == COLUMNS_NUM || position == z){
convertView.setLayoutParams(new AbsListView.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, mActionBarHeight - 15));
}
return convertView;
}
View v = convertView;
if(v == null){
v = LayoutInflater.from(mContext).inflate(R.layout.player_movie, null);
v.setLayoutParams(mImageViewLayoutParams);
}
TextView title = (TextView) v.findViewById(R.id.serial_title);
TextView seria = (TextView) v.findViewById(R.id.when);
ImageView poster = (ImageView) v.findViewById(R.id.poster);
//Offten.debug(getCount(), position);
int x = (position - (COLUMNS_NUM * 2) )< mArray.get(0).size() ? position - (COLUMNS_NUM * 2) : position - (z + COLUMNS_NUM);
int y = (position - (COLUMNS_NUM * 2) )< mArray.get(0).size() ? 0 : 1;
// Offten.debug(x + " " + (position < mArray.get(0).size() ? "true" : "false") + " " + mArray.get(0).size());
//Offten.debug( Boolean.toString((position - (COLUMNS_NUM * 2) )< mArray.get(0).size()) + " " + x + " " + z);
Serial serial = mArray.get(y).get(x);
title.setText(serial.getTitle());
seria.setText(serial.getSeria());
mFetcher.loadImage( serial.getPoster(), poster);
if(v.getLayoutParams().height != mItemHeight){
v.setLayoutParams(mImageViewLayoutParams);
}
return v;
}
public TextView header(int message, View convertView){
TextView view = (TextView) convertView; // issue with cast exception
if(view == null){
view = new TextView(mContext);
}
view.setText(underline(mContext.getResources().getString(message)));
view.setTextSize(18);
view.setTypeface(typeface, Typeface.BOLD_ITALIC);
view.setTextColor(Color.WHITE);
view.setGravity(Gravity.CENTER_VERTICAL);
view.setLayoutParams(new AbsListView.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, mActionBarHeight - 15));
return view;
}
With this code i always have issue with cast exception in my header TextView. (View cannot be cast to TextView)
#Override
public int getViewTypeCount() {
// Two types of views, the normal ImageView and the top row of empty views
return 2;
}
#Override
public int getCount() {
int size = 0;
for(List<Serial> s : mArray){
size += s.size() + COLUMNS_NUM;
}
return size > 0 ? size + COLUMNS_NUM : size;
}
#Override
public int getItemViewType(int position) {
int size = mArray.get(0).size();
int z = size + (COLUMNS_NUM * 2);
return position < (COLUMNS_NUM * 2) || (position > (z -1) && position < (z + COLUMNS_NUM)) ? 1 : 0;
}
can i solve my problem??
Do like this
public TextView header(int message, View convertView){
TextView view = (TextView) convertView.findViewById(R.id.<textviewId>); // issue with cast exception
if(view == null){
view = new TextView(mContext);
}
view.setText(underline(mContext.getResources().getString(message)));
view.setTextSize(18);
view.setTypeface(typeface, Typeface.BOLD_ITALIC);
view.setTextColor(Color.WHITE);
view.setGravity(Gravity.CENTER_VERTICAL);
view.setLayoutParams(new AbsListView.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, mActionBarHeight - 15));
return view;
}
So i fount answer for my question! i have 3 difference view, but i declareted only 2, and i had problems! Thanks for all to helping!
#Override
public int getItemViewType(int position) {
int size = mArray.get(0).size();
int z = size + (COLUMNS_NUM * 2);
if (position < (COLUMNS_NUM * 2) || (position > (z -1) && position < (z + COLUMNS_NUM))) {
if(position == COLUMNS_NUM || position == z){
return 1;
}
return 2;
}
return 0;
}
#Override
public int getViewTypeCount() {
// Two types of views, the normal ImageView and the top row of empty views
return 3;
}
I have a GridView with the following properties:
<GridView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/PhoneImageGrid"
style="#style/PhotoGridLayout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:alwaysDrawnWithCache="true"
android:clipChildren="true"
android:columnWidth="100dp"
android:horizontalSpacing="2dp"
android:numColumns="auto_fit"
android:padding="4dp"
android:scrollbars="none"
android:scrollingCache="true"
android:smoothScrollbar="true"
android:stretchMode="columnWidth"
android:verticalSpacing="4dp" />
Here is the grid item:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<ImageView
android:id="#+id/thumbImage"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
<CheckBox
android:id="#+id/itemCheckBox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true" />
</RelativeLayout>
Now when when i run the app, i got a gridview, looks everything right in portrait and when i turn it to landscape the col width is being changed but i want the contents of the item also to be scaled proportionately according to the new col width(item_height = item_width = new col width). How can i achieve this? Thanks
Its bit tricky to set get the gridview col width. One you got the col width you can set the imageview height to the col width and notify adapter of changes. (code taken from the android samples: https://developer.android.com/training/displaying-bitmaps/index.html)
Here's the way to measure the col width:
imagegrid.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
if (imageAdapter.getNumColumns() == 0) {
final int numColumns = (int) Math.floor(imagegrid.getWidth()
/ (mImageThumbSize + mImageThumbSpacing));
if (numColumns > 0) {
final int columnWidth = (imagegrid.getWidth() / numColumns) - mImageThumbSpacing;
imageAdapter.setNumColumns(numColumns);
imageAdapter.setItemHeight(columnWidth);
}
}
}
});
Create these methods in the Adapter:
public void setNumColumns(int numColumns) {
mNumColumns = numColumns;
}
public int getNumColumns() {
return mNumColumns;
}
public void setItemHeight(int height) {
if (height == mItemHeight) {
return;
}
mItemHeight = height;
mImageViewLayoutParams = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, mItemHeight);
// mImageFetcher.setImageSize(height);
notifyDataSetChanged();
}
Set the initial image size as:
mImageViewLayoutParams = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT);
Here's the complete adapter class:
public class ImageAdapter extends BaseAdapter {
private LayoutInflater mInflater;
private int mItemHeight = 0;
private int mNumColumns = 0;
private RelativeLayout.LayoutParams mImageViewLayoutParams;
public ImageAdapter() {
mInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mImageViewLayoutParams = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT);
}
public void setNumColumns(int numColumns) {
mNumColumns = numColumns;
}
public int getNumColumns() {
return mNumColumns;
}
public void setItemHeight(int height) {
if (height == mItemHeight) {
return;
}
mItemHeight = height;
mImageViewLayoutParams = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, mItemHeight);
// mImageFetcher.setImageSize(height);
notifyDataSetChanged();
}
public int getCount() {
return images.size();
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
holder = new ViewHolder();
convertView = mInflater.inflate(R.layout.galleryitem, null);
holder.imageview = (ImageView) convertView.findViewById(R.id.thumbImage);
holder.checkbox = (CheckBox) convertView.findViewById(R.id.itemCheckBox);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
ImageItem item = images.get(position);
holder.imageview.setId(position);
// holder.imageview.setImageBitmap(item.img);
holder.imageview.setLayoutParams(mImageViewLayoutParams);
// Check the height matches our calculated column width
if (holder.imageview.getLayoutParams().height != mItemHeight) {
holder.imageview.setLayoutParams(mImageViewLayoutParams);
}
holder.imageview.setImageBitmap(item.img);
holder.checkbox.setChecked(item.selection);
return convertView;
}
}