I have a custom TextView which I'm using in a custom GridView adapter. The custom TextView is using a custom font for translation purposes. This works fairly well in devices which have the locale installed by default.
However, in devices, in which the language is not installed, it is displaying a strange behavior. When the app loads the first time, the TextViews don't display with the custom font. However when I press the refresh button to reload the fragment, the TextViews display with the custom font.
I'm not sure why this is happening.
This is happening with all the custom Adapters in my application in which I'm using the custom TextView.
Pretty basic adapter:
public class CalendarWeekAdapter extends BaseAdapter{
private String[] weekdays;
Context mContext;
private LayoutInflater mInflater;
public CalendarWeekAdapter(Context context, int firstDay)
{
mContext=context;
mInflater = LayoutInflater.from(context);
weekdays = context.getResources().getStringArray(R.array.weekdays);
}
public int getCount()
{
return weekdays.length;
}
public Object getItem(int position)
{
return position;
}
public long getItemId(int position)
{
return position;
}
public View getView(int position, View convertView, ViewGroup parent)
{
ViewHolder holder=null;
if(convertView==null)
{
convertView = mInflater.inflate(R.layout.calendar_week, parent,false);
holder = new ViewHolder();
holder.txtWeekdays=(CustomTextView)convertView.findViewById(R.id.weekdays);
if(position==0)
{
convertView.setTag(holder);
}
}
else
{
holder = (ViewHolder) convertView.getTag();
}
holder.txtWeekdays.setText(weekdays[position]);
return convertView;
}
}
class ViewHolder
{
CustomTextView txtWeekdays;
}
Basic CustomTextView:
public class CustomTextView extends TextView {
public CustomTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
public CustomTextView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public CustomTextView(Context context) {
super(context);
init();
}
private void init() {
if (!isInEditMode()) {
setTypeface(Utils.getFont(getContext()));
}
}
}
This is may not be the answer, but i don't understand this if-statement:
holder.txtWeekdays=(CustomTextView)convertView.findViewById(R.id.weekdays);
if(position==0)
{
convertView.setTag(holder);
}
Why is it there? All your newly inflated convertViews should have holder as their tag.
Just remove the 'if' around the convertView.setTag(holder):
if(convertView==null)
{
convertView = mInflater.inflate(R.layout.calendar_week, null,false);
holder = new ViewHolder();
holder.txtWeekdays=(CustomTextView)convertView.findViewById(R.id.weekdays);
convertView.setTag(holder);
}
...
and see if this will improve or even fix your situation.
Related
I tried to migrate my Chat Bot from ScrollView to a RecyclerView for performance, but unfortunally every method in my Adapter is called correctly but nothing is showed.
My Custom RecyclerView Adapter:
public class ChatViewAdapter extends RecyclerView.Adapter<ChatViewAdapter.ChatViewHolder> {
private LinkedList<ChatBubbleModel> bubbles;
private ViewGroup group;
public ChatViewAdapter() {
this(new LinkedList<ChatBubbleModel>());
}
public ChatViewAdapter(LinkedList<ChatBubbleModel> bubbles) {
this.bubbles = bubbles;
}
public LinkedList<ChatBubbleModel> getBubbles() {
return bubbles;
}
public void addBubble(ChatBubbleModel bubble) {
this.bubbles.add(bubble);
notifyDataSetChanged();
}
#NonNull
#Override
public ChatViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
this.group = parent;
return new ChatViewHolder(new TextView(parent.getContext()));
}
#Override
public void onBindViewHolder(#NonNull ChatViewHolder holder, int position) {
final ChatBubbleModel instance = this.bubbles.get(position);
if (instance.getUserType() == ChatBubbleModel.UserType.USER) {
holder.setTextView(new RightChatBubble(instance.getOwner(), instance.getMessage(), group.getContext()));
} else {
holder.setTextView(new LeftChatBubble(instance.getOwner(), instance.getMessage(), group.getContext()));
}
}
#Override
public int getItemCount() {
return this.bubbles.size();
}
public static class ChatViewHolder extends RecyclerView.ViewHolder {
// each data item is just a string in this case
private TextView textView;
public ChatViewHolder(TextView v) {
super(v);
textView = v;
}
public void setTextView(TextView view) {
this.textView = view;
}
}
}
And in the Fragmnet where I use it:
final View root = inflater.inflate(R.layout.fragment_chatview, container, false);
chatView = root.findViewById(R.id.chatView);
chatView.setHasFixedSize(true);
layoutManager = new LinearLayoutManager(getContext());
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
chatView.setLayoutManager(layoutManager);
this.chatAdapter = new ChatViewAdapter(new LinkedList<ChatBubbleModel>());
chatView.setAdapter(chatAdapter);
The Impl of the View I use:
public class LeftChatBubble extends androidx.appcompat.widget.AppCompatTextView {
private final static int leftRightPadding = 50;
private final static int topBottomPadding = 20;
public LeftChatBubble(Context context) {
this(context, null, -1);
}
#SuppressLint("SetTextI18n")
public LeftChatBubble(String owner, String text, Context context) {
super(context);
setText(owner + "\n" + text);
setBackground(ContextCompat.getDrawable(context, R.drawable.inset));
setPadding(pixelToDp(leftRightPadding, context), pixelToDp(topBottomPadding, context), pixelToDp(leftRightPadding, context), pixelToDp(topBottomPadding, context));
setTextAlignment(TEXT_ALIGNMENT_VIEW_START);
setTextColor(Color.WHITE);
}
public LeftChatBubble(Context context, #Nullable AttributeSet attrs) {
this(context, attrs, -1);
}
public LeftChatBubble(Context context, #Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setBackground(ContextCompat.getDrawable(context, R.drawable.ic_chatbubleleft));
setPadding(pixelToDp(leftRightPadding, context), pixelToDp(topBottomPadding, context), pixelToDp(leftRightPadding, context), pixelToDp(topBottomPadding, context));
setTextAlignment(TEXT_ALIGNMENT_VIEW_START);
setTextColor(Color.WHITE);
}
private int pixelToDp(int px, Context context) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (px * scale + 0.5f);
}
}
Does anyone have an Idea why there is nothing showed on the device? The Used Layout is correct bc it worked before.
You did not seem to inflate your item view in the onCreateViewHolder like
#NonNull
#Override
public ChatViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
this.group = parent;
LayoutInflater inflater = LayoutInflater.from(this);
View view = inflater.inflate(R.layout.item_view, parent, false);
return new ChatViewHolder(view);
}
Also, change your ViewHolder args to be a View.
The Problem was that I not created the Correct View Class in onCreate Mathod of Adapter...
But thank you all for your helpful answers.
The user select a image, the path of the image is then stored in my SQLite database. I then populate the text/images from SQLite in a GridView using a CursorAdapter:
public class MyNiftyAdapter extends CursorAdapter{
private LayoutInflater mInflater;
private Cursor cur;
public MyNiftyAdapter(Context context, Cursor c) {
super(context,c);
this.mInflater = LayoutInflater.from(context);
this.cur = c;
}
public MyNiftyAdapter(Context context, Cursor c, boolean autoRequery)
{
super(context, c, autoRequery);
this.mInflater = LayoutInflater.from(context);
this.cur = c;
}
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
ViewHolder viewHolder;
if(convertView == null)
{
convertView = this.mInflater.inflate(R.layout.single_item, null);
viewHolder = new ViewHolder();
viewHolder.name = (TextView)convertView.findViewById(R.id.txtName);
viewHolder.Age = (TextView)convertView.findViewById(R.id.studentage);
viewHolder.Id = (TextView)convertView.findViewById(R.id.rowid);
viewHolder.Image = (CircularImageView)convertView.findViewById(R.id.imgFood);
convertView.setTag(viewHolder);
}else
{
viewHolder = (ViewHolder)convertView.getTag();
}
this.cur.moveToPosition(position);
viewHolder.name.setText(this.cur.getString(this.cur.getColumnIndex(SQLiteHelper.NAME)));
viewHolder.Age.setText(this.cur.getString(this.cur.getColumnIndex(SQLiteHelper.AGE)));
viewHolder.Id.setText(this.cur.getString(this.cur.getColumnIndex(SQLiteHelper._ID)));
Uri jg = Uri.parse(this.cur.getString(this.cur.getColumnIndex("imagepath")));
viewHolder.Image.setImageURI(jg);
return convertView;
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
// Dont need to do anything here
return null;
}
static class ViewHolder
{
TextView name;
TextView Age;
TextView Id;
CircularImageView Image;
}
}
When I select large images I get a out of memory error:
java.lang.OutOfMemoryError: Failed to allocate a 21566748 byte allocation with 8448604 free bytes and 8MB until OOM
I have seen that the bitmap should be scaled down, but I'm just using the Uri of the file and displaying it. Is there anyway to avoid this issue as I don't want to save another(compressed) file to the device?
I have tried android:hardwareAccelerated="false" in manifest.
This is what worked for me:
I ended up using picasso as the answers suggested, but something important to note is that when loading a URI from device is to load the URI like this:
Picasso.with(mContext)
.load(new File(String.valueOf(Uri)))
.placeholder(R.drawable.profile)
.resize(800, 800)
.centerCrop()
.into(viewHolder.Image);
note that I used .load(new File(String.valueOf(Uri))) instead of .load(uri).
If you load the URI directly the view will return empty.
If you load a image from a url, it should be loaded like this:
Picasso.with(mContext)
.load(URL)
.placeholder(R.drawable.profile)
.resize(800, 800)
.centerCrop()
.into(viewHolder.Image);
So my adapter ended up looking like this:
public class MyNiftyAdapter extends CursorAdapter{
private LayoutInflater mInflater;
private Cursor cur;
private Context mContext;
public MyNiftyAdapter(Context context, Cursor c) {
super(context,c);
this.mInflater = LayoutInflater.from(context);
this.mContext = context;
this.cur = c;
}
public MyNiftyAdapter(Context context, Cursor c, boolean autoRequery)
{
super(context, c, autoRequery);
this.mInflater = LayoutInflater.from(context);
this.cur = c;
this.mContext = context;
}
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
ViewHolder viewHolder;
if(convertView == null)
{
convertView = this.mInflater.inflate(R.layout.single_item, null);
viewHolder = new ViewHolder();
viewHolder.name = (TextView)convertView.findViewById(R.id.txtName);
viewHolder.Age = (TextView)convertView.findViewById(R.id.studentage);
viewHolder.Id = (TextView)convertView.findViewById(R.id.rowid);
viewHolder.Image = (CircularImageView)convertView.findViewById(R.id.imgFood);
convertView.setTag(viewHolder);
}else
{
viewHolder = (ViewHolder)convertView.getTag();
}
this.cur.moveToPosition(position);
viewHolder.name.setText(this.cur.getString(this.cur.getColumnIndex(SQLiteHelper.NAME)));
viewHolder.Age.setText(this.cur.getString(this.cur.getColumnIndex(SQLiteHelper.AGE)));
viewHolder.Id.setText(this.cur.getString(this.cur.getColumnIndex(SQLiteHelper._ID)));
Uri jg = Uri.parse(this.cur.getString(this.cur.getColumnIndex("imagepath")));
Picasso.with(mContext)
.load(new File(String.valueOf(jg)))
.placeholder(R.drawable.profile)
.resize(800, 800)
.centerCrop()
.into(viewHolder.Image);
return convertView;
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
// Dont need to do anything here
return null;
}
static class ViewHolder
{
TextView name;
TextView Age;
TextView Id;
CircularImageView Image;
}
}
Thank you all for the help.
You can use Picasso library to display images.
compile 'com.squareup.picasso:picasso:2.5.2'
And in your adapter something like this :
Uri jg = Uri.parse(this.cur.getString(this.cur.getColumnIndex("imagepath")));
Picasso.with(context).load(jg).into(viewHolder.Image);
For Context
public class MyNiftyAdapter extends CursorAdapter{
private LayoutInflater mInflater;
private Cursor cur;
private Context mContext;
public MyNiftyAdapter(Context context, Cursor c) {
super(context,c);
this.mInflater = LayoutInflater.from(context);
this.mContext= context;
this.cur = c;
}
public MyNiftyAdapter(Context context, Cursor c, boolean autoRequery)
{
super(context, c, autoRequery);
this.mInflater = LayoutInflater.from(context);
this.cur = c;
this.mContext= context;
}
an then use :
Uri jg = Uri.parse(this.cur.getString(this.cur.getColumnIndex("imagepath")));
Picasso.with(mContext).load(jg).into(viewHolder.Image);
i have class adapter that contain image view and text view , i receive arraylist from the post excute then pass this array to the my adapter, when run my application it's give me this error.
java.lang.NullPointerException: Attempt to read from field 'android.widget.ImageView com.gmplatform.gmp.MainActivity_navagation_custmoer$itemAdapter3$ViewHolder.ivpic1' on a null object reference
at com.gmplatform.gmp.MainActivity_navagation_custmoer$itemAdapter3$ViewHolder.access$2600(MainActivity_navagation_custmoer.java:2410)
at com.gmplatform.gmp.MainActivity_navagation_custmoer$itemAdapter3.getView(MainActivity_navagation_custmoer.java:2372)
below here the adapter class
public class itemAdapter3 extends BaseAdapter{
private ArrayList<favouriteitems> itemCatalog;
private int resource;
private LayoutInflater inflater;
public itemAdapter3(Context context, int resource, List<favouriteitems> objects) {
// super(context, resource, objects);
itemCatalog = (ArrayList<favouriteitems>) objects;
this.resource = resource;
inflater = (LayoutInflater) getApplicationContext().getSystemService(LAYOUT_INFLATER_SERVICE);
}
public void notifyDataSetChanged() {
super.notifyDataSetChanged();
}
#Override
public int getCount() {
return itemCatalog.size();
}
#Override
public Object getItem(int position) {
return itemCatalog.get(position);
}
#Override
public long getItemId(int position) {
return itemCatalog.indexOf(getItem(position));
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
final int pos = position;
final favouriteitems items = itemCatalog.get(pos);
ViewHolder holder = null;
if (convertView == null) {
holder = new ViewHolder();
convertView = inflater.inflate(resource, null);
holder.ivpic1 = (ImageView) convertView.findViewById(R.id.iv);
holder.st = (ImageView)convertView.findViewById(R.id.st);
holder.sh=(ImageView)convertView.findViewById(R.id.sh);
holder.name = (TextView) convertView.findViewById(R.id.t4);
holder.pr = (TextView) convertView.findViewById(R.id.textView32);
holder.av = (TextView) convertView.findViewById(R.id.av);
holder.t5 = (TextView) convertView.findViewById(R.id.t5);
final ViewHolder finalHolder = holder;
}
else {
holder = (MainActivity_navagation_custmoer.itemAdapter3.ViewHolder) convertView.getTag();
}
final ProgressBar progressBar = (ProgressBar) convertView.findViewById(R.id.progressBar);
// Then later, when you want to display image
ImageLoader.getInstance().displayImage(itemCatalog.get(position).getM1().getLoc2().getItmc().getIt().getPic(), holder.ivpic1 , new ImageLoadingListener() {
#Override
public void onLoadingStarted(String imageUri, View view) {
progressBar.setVisibility(View.VISIBLE);
}
#Override
public void onLoadingFailed(String imageUri, View view, FailReason failReason) {
progressBar.setVisibility(View.GONE);
}
#Override
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
progressBar.setVisibility(View.GONE);
}
#Override
public void onLoadingCancelled(String imageUri, View view) {
progressBar.setVisibility(View.GONE);
}
});
holder.pr.setText(String.valueOf(itemCatalog.get(position).getM1().getLoc2().getItmc().getPrice() + " SR"));
holder.name.setText(itemCatalog.get(position).getM1().getLoc2().getItmc().getIt().getName());
if (itemCatalog.get(position).getM1().getLoc2().getItmc().isInSc() == true) {
holder.sh.setImageResource(R.drawable.customern2);
} else {
holder.sh.setImageResource(R.drawable.customern1);
}
holder.t5.setText(itemCatalog.get(position).getM1().getmName()+" ("+itemCatalog.get(position).getM1().getLoc2().getArea()+" )");
return convertView;
}
class ViewHolder {
private ImageView ivpic1,sh,st;
private TextView name,pr,t5,av;
}
}
There is a problem in your Constructor:
Uncomment the super call and run it, you will stop getting null pointer exception.
public itemAdapter3(Context context, int resource, List<favouriteitems> objects) {
super(context, resource, objects);
itemCatalog = (ArrayList<favouriteitems>) objects;
this.resource = resource;
inflater = (LayoutInflater) getApplicationContext().getSystemService(LAYOUT_INFLATER_SERVICE);
}
> holder = (ViewHolder) convertView.getTag();
you donot have a corrensponding convertView.setTag(holder) after the holder was created with holder = new ViewHolder();.
I have a simple GridView with custom Adapter in my layouts. My code is as follows:
CircleActivity.java:
public class CircleActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_circle);
List<Integer> listColors = new ArrayList<>();
listColors.add(getResources().getColor(R.color.colorAccent));
listColors.add(getResources().getColor(R.color.colorPrimary));
listColors.add(getResources().getColor(R.color.colorPrimaryDark));
GridView gridView = (GridView) findViewById(R.id.grid_colors);
CircleAdapter adapter = new CircleAdapter(this,listColors);
gridView.setAdapter(adapter);
}
}
activity_circle.xml:
<?xml version="1.0" encoding="utf-8"?>
<GridView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/grid_colors"
android:layout_width="match_parent"
android:layout_height="match_parent" />
CircleAdapter.java:
public class CircleAdapter extends BaseAdapter{
private Context context;
private List<Integer> listColor;
public CircleAdapter(Context context, List<Integer> listColor) {
this.listColor = listColor;
this.context = context;
}
#Override
public int getCount() {
return listColor.size();
}
#Override
public Integer getItem(int position) {
return listColor.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if(convertView==null){
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.row_grid,parent,false);
holder = new ViewHolder(convertView);
convertView.setTag(holder);
}
else{
holder = (ViewHolder) convertView.getTag();
}
holder.customCircleView.setFillColor(listColor.get(position));
holder.customCircleView.setCircleRadius(100);
return convertView;
}
static class ViewHolder{
private CustomCircleView customCircleView;
public ViewHolder(View row){
customCircleView = (CustomCircleView) row.findViewById(R.id.custom_circle_view);
}
}
}
row_grid.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:background="#color/colorAccent"
android:layout_width="match_parent"
android:gravity="center"
android:layout_height="match_parent">
<com.droidexperiments.gridexpand.CustomCircleView
android:id="#+id/custom_circle_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
custom:fill_color="#color/colorPrimary"
custom:circle_radius="50"
android:padding="25dp" />
</LinearLayout>
CircleView.java:
public class CustomCircleView extends View {
private int circleRadius = 20;
private int fillColor = Color.BLACK;
public CustomCircleView(Context context) {
super(context);
}
public CustomCircleView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public CustomCircleView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
public CustomCircleView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
TypedArray typedArray = context.obtainStyledAttributes(R.styleable.CustomCircle);
circleRadius = typedArray.getInteger(R.styleable.CustomCircle_circle_radius,20);
fillColor = typedArray.getColor(R.styleable.CustomCircle_fill_color, Color.BLACK);
typedArray.recycle();
}
public int getCircleRadius() {
return circleRadius;
}
public void setCircleRadius(int circleRadius) {
this.circleRadius = circleRadius;
}
public int getFillColor() {
return fillColor;
}
public void setFillColor(int fillColor) {
this.fillColor = fillColor;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint = new Paint();
paint.setColor(fillColor);
paint.setStyle(Paint.Style.FILL);
canvas.drawCircle(canvas.getWidth()/2,canvas.getHeight()/2,circleRadius,paint);
}
}
attrts.xml:
<declare-styleable name="CustomCircle">
<attr name="fill_color" format="reference|color"/>
<attr name="circle_radius" format="integer"/>
</declare-styleable>
The issue is that screen remains blank and no row is inflated/showing in GridView.
I have checked everything. There is not any issue in GridView or the layout of grid row or in CustomCircleView. If I change adapter to simple ArrayAdapter, it works fine. So, there must be issue with my adapter:
I double checked getView() in adapter;
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if(convertView==null){
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.row_grid,parent,false);
holder = new ViewHolder(convertView);
convertView.setTag(holder);
}
else{
holder = (ViewHolder) convertView.getTag();
}
holder.customCircleView.setFillColor(listColor.get(position));
holder.customCircleView.setCircleRadius(100);
return convertView;
}
but couldn't identify why it shows blank. can anyone help me please?
When you implement a custom view, it is essential that you implement onMeasure. This method will tell the Android framework what size your view should be. Since you didn't specify this for CustomCircleView and used wrap_content in your layout, it had size zero. Therefore, all the elements of the GridView were invisible, making it look like the adapter was not working. I made a simple example implementation of onMeasure that solves your problem (just add this method in CustomCircleView):
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int size = View.MeasureSpec.makeMeasureSpec(2 * this.circleRadius, MeasureSpec.EXACTLY);
setMeasuredDimension(size, size);
}
The documentation advises that size stays within the given parameters (widthMeasureSpec and heightMeasureSpec). I have not included that restriction here, you can determine yourself what you want to do in that case.
You can find more information about this in the guide on creating custom components. Specific information about onMeasure can be found here.
I have a custom ListView with a TextView and a CheckBox. I also have a custom SimpleAdapter in which I override the getView() method and am able to retrieve clicks on the TextView and CheckBox changes. My problem is that I don't know how to get the correct clicked ListItem or CheckBox inside the OnCheckedChanged or OnClick.
UPDATE added whole CustomAdapter class:
public class CustomAdapter extends SimpleAdapter {
private LayoutInflater mInflater;
private List<HashMap<String, String>> mItems = null;
private Context mContext;
private int mPosicion;
public CustomAdapter(Context context, List<HashMap<String, String>> items, int resource, String[] from, int[] to) {
super(context, items, resource, from, to);
mInflater = LayoutInflater.from(context);
mItems = items;
mContext = context;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
mPosicion = position;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.custom_row_view, null);
holder = new ViewHolder();
holder.chkbxEstado = (CheckBox) convertView.findViewById(R.id.chkbxCompletado);
holder.txtTextoAgenda = (TextView) convertView.findViewById(R.id.txtTextoLista);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.txtTextoAgenda.setText(mItems.get(position).get("descripcion"));
convertView.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Log.i("Posicion",""+mPosicion);//I don't know how to retrieve clicked position
}
});
holder.chkbxEstado.setOnCheckedChangeListener(new OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
Log.i("Posicion",""+mPosicion);//Or checked
}
});
return convertView;
}
private static class ViewHolder {
TextView txtTextoAgenda;
CheckBox chkbxEstado;
}
}
Any help is appreciated.
I found a solution. If anybody knows a better one, please let me know. Working CustomAdapter class:
public class CustomAdapter extends SimpleAdapter {
private LayoutInflater mInflater;
private List<HashMap<String, String>> mItems = null;
private Context mContext;
private OnClickListener mClick;
private OnCheckedChangeListener mChecked;
public CustomAdapter(Context context, List<HashMap<String, String>> items, int resource, String[] from, int[] to) {
super(context, items, resource, from, to);
mInflater = LayoutInflater.from(context);
mItems = items;
mContext = context;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.custom_row_view, null);
holder = new ViewHolder();
holder.chkbxEstado = (CheckBox) convertView.findViewById(R.id.chkbxCompletado);
holder.txtTextoAgenda = (TextView) convertView.findViewById(R.id.txtTextoLista);
holder.posicion = position; //Add the new position into the holder for each row.
convertView.setTag(holder);
mClick = new OnClickListener() {
#Override
public void onClick(View v) {
ViewHolder viewHolder = getViewHolder(v); //Get the ViewHolder for the clicked row.
Log.i("Posicion",""+v.posicion);
}
};
mChecked = new OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
ViewHolder viewHolder = getViewHolder(buttonView); //Get the ViewHolder for the clicked CheckBox
Log.i("Posicion",""+viewHolder.posicion);
}
};
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.txtTextoAgenda.setText(mItems.get(position).get("descripcion"));
convertView.setOnClickListener(mClick);
holder.chkbxEstado.setOnCheckedChangeListener(mChecked);
return convertView;
}
public ViewHolder getViewHolder(View v){ //This method returns the ViewHolder stored in the tag if available, if not it recursively checks the parent's tag.
if(v.getTag() == null){
return getViewHolder((View)v.getParent());
}
return (ViewHolder)v.getTag();
}
private static class ViewHolder {
TextView txtTextoAgenda;
CheckBox chkbxEstado;
int posicion; //Added position attribute to ViewHolder class.
}
}
Edited to re-use onClickListener() and onCheckedChangedListener() instances.
The OP's solution works. But if you are extending a CursorAdapter, the position parameter does not exist in newView() and bindView(). What to do?
They do supply a Cursor. Use cursor.getPosition(). It does the same thing.