I am creating an Android app using Android Studio.
I have listview in an activity that is using a custom SimpleAdapter.
I need to use a custom font in the custom adapter but when I try it does not work.
No errors only no font is being used. The font path works fine when used directly in an activity.
When I log out the fonter created I get this:
E/====﹕ FONT: android.graphics.Typeface#4c5dfbc0
This is my custom adapter code:
package com.myapp.app.utilities;
import android.content.Context;
import android.graphics.Color;
import android.graphics.Typeface;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.SimpleAdapter;
import android.widget.TextView;
import com.fieldly41.app.R;
import java.util.ArrayList;
import java.util.HashMap;
public class SimpleIconAdapter extends SimpleAdapter {
private ArrayList<HashMap<String, String>> results;
//private Context context;
Typeface font;
public SimpleIconAdapter(Context context, ArrayList<HashMap<String, String>> data, int resource, String[] from, int[] to) {
super(context, data, resource, from, to);
this.results = data;
}
#Override
public View getView(int position, View view, ViewGroup parent) {
View v = view;
if (v == null) {
LayoutInflater inflater = (LayoutInflater) parent.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = inflater.inflate(R.layout.list_item_icon, null);
}
if(results.get(position) != null ) {
Typeface fonter = Typeface.createFromAsset(v.getResources().getAssets(), "fonts/ss-symbolicons-line.ttf");
TextView top_label = (TextView) v.findViewById(R.id.top_label);
TextView icon_label = (TextView) v.findViewById(R.id.icon);
TextView bottom_label = (TextView) v.findViewById(R.id.bottom_label);
icon_label.setText("💀");
icon_label.setTypeface(fonter);
if (results.get(position).get("locked").equals("false")) {
icon_label.setTextColor(Color.WHITE);
} else {
icon_label.setTextColor(Color.RED);
}
top_label.setText(results.get(position).get("title"));
bottom_label.setText(results.get(position).get("created_at"));
}
return v;
}
}
Your implementations is near to ok.
But the big problem is you are creating a TypeFace instance in getView() method which is very resource hungry.
Because getView() method calls repeatedly N numbers of time whenever you scroll the list.
And loading resource from assets extensively is bad practice, it may cause OutOfMemoryError any time.
So my recommendation is create common object and use in getView().
public SimpleIconAdapter(Context context, ArrayList<HashMap<String, String>> data, int resource, String[] from, int[] to) {
super(context, data, resource, from, to);
font=Typeface.createFromAsset(context.getAssets(), "fonts/ss-symbolicons-line.ttf");
this.results = data;
}
In getView() remove this Line
Typeface fonter = Typeface.createFromAsset(v.getResources().getAssets(), "fonts/ss-symbolicons-line.ttf");
And use "font" object instead fonter
icon_label.setTypeface(font);
Try this way,hope this will help you to solve your problem.
Since it's a listview, I would suggest you to create a custom textview and take it inside the row layout xml.
Note: It's important that you place required font files in the assets folder.
Create Custom TextView with your custom font.
CustomTextView.java
public class CustomTextView extends TextView {
public CustomTextView(Context context) {
super(context);
setFont();
}
public CustomTextView(Context context, AttributeSet attrs) {
super(context, attrs);
setFont();
}
public CustomTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setFont();
}
private void setFont() {
Typeface font = Typeface.createFromAsset(getContext().getAssets(),"fonts/ss-symbolicons-line.ttf");
setTypeface(font, Typeface.NORMAL);
}
}
Try define Custom TextView instead of simple TextView which you would like to shown your custom font.
list_item_icon.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="#+id/top_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<yourpackagename.CustomTextView
android:id="#+id/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"/>
<TextView
android:id="#+id/bottom_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"/>
</LinearLayout>
Care about Custom TextView declaration and initialization and try to use ViewHolder concept when you use Custom adapter.
public class SimpleIconAdapter extends SimpleAdapter {
private Context context;
private ArrayList<HashMap<String, String>> results;
public SimpleIconAdapter(Context context, ArrayList<HashMap<String, String>> data, int resource, String[] from, int[] to) {
super(context, data, resource, from, to);
this.results = data;
this.context=context;
}
#Override
public View getView(int position, View view, ViewGroup parent) {
ViewHolder holder;
if (view == null) {
holder = new ViewHolder();
view = LayoutInflater.from(context).inflate(R.layout.list_item_icon, null);
holder.top_label = (TextView) view.findViewById(R.id.top_label);
holder.icon_label = (CustomTextView) view.findViewById(R.id.icon);
holder.bottom_label = (TextView) view.findViewById(R.id.bottom_label);
view.setTag(holder);
}else{
holder = (ViewHolder) view.getTag();
}
holder.icon_label.setText("💀");
if (results.get(position).get("locked").equals("false")) {
holder.icon_label.setTextColor(Color.WHITE);
} else {
holder.icon_label.setTextColor(Color.RED);
}
holder.top_label.setText(results.get(position).get("title"));
holder.bottom_label.setText(results.get(position).get("created_at"));
return view;
}
class ViewHolder{
TextView top_label;
CustomTextView icon_label;
TextView bottom_label;
}
}
Related
I'm creating an app where there is a listview of apps activity, each app has an on click listener that opens an activity with app infotmation.
This is the Application class:
public class Application {
private String title;
private String imageUrl;
private ArrayList<String> appVersions;
public Application(String title, String imageUrl, ArrayList<String> appVersions) {
this.title = imageName;
this.imageUrl = imageUrl;
this.appVersions = appVersions;
}
public String getTitle() {
return title;
}
public void setTitle(String imageName) {
this.title = imageName;
}
public String getImageUrl() {
return imageUrl;
}
public void setImageUrl(String imageUrl) {
this.imageUrl = imageUrl;
}
public ArrayList<String> getAppVersions() {
return appVersions;
}
public void setAppVersions(ArrayList<String> appVersions) {
this.appVersions = appVersions;
}
}
and this is the ApplicationVersionAdapter class:
import java.util.ArrayList;
public class ApplicationVersionAdapter extends ArrayAdapter<Application> {
private static final String TAG = "ApplicationVersionAdapt";
private Context mContext;
private int mResource;
public ApplicationVersionAdapter(#NonNull Context context, int resource, #NonNull ArrayList<Application> objects) {
super(context, resource, objects);
this.mContext = context;
this.mResource = resource;
}
#NonNull
#Override
public View getView(int position, #Nullable View convertView, #NonNull ViewGroup parent) {
String appVersion = getItem(position).getAppVersions().get(position);
// String appVersion = getItem(position).getImageName();
Log.d("Application version: ", getItem(position).getAppVersions().get(position));
LayoutInflater inflater = LayoutInflater.from(mContext);
convertView = inflater.inflate(mResource, parent, false);
TextView tvAppVersion = convertView.findViewById(R.id.app_version);
tvAppVersion.setText(appVersion);
return convertView;
}
}
and in gallery activity I set the adapter:
ApplicationVersionAdapter adapter = new ApplicationVersionAdapter(this,
R.layout.layout_appversion, list);
appVersionsList.setAdapter(adapter);
Each application object has versions:
Application 1:
name: app1
image: imageUrl
versions: v 1.0
v 1.1
v 1.2
Gallery layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"
android:weightSum="100">
<ImageView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="50"
android:id="#+id/image"
android:scaleType="centerCrop"
android:src="#mipmap/ic_launcher_round"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/image_description"
android:layout_marginLeft="10dp"
android:layout_marginTop="10dp"
android:text="Canada"
android:textColor="#000"/>
<ListView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="40"
android:id="#+id/app_versions">
</ListView>
</LinearLayout>
how to populate the list of application versions in the gallery activity?
Update
This is my RecyclerViewAdapter for the list of applications in main activity, I'm using images to fill the list not the application class but I will put the RecyclerViewAdapter to see the onClick listener:
import android.content.Context;
import android.content.Intent;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.bumptech.glide.Glide;
import java.util.ArrayList;
import de.hdodenhof.circleimageview.CircleImageView;
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder>{
private static final String TAG = "RecyclerViewAdapter";
private ArrayList<String> mImageNames = new ArrayList<>();
private ArrayList<String> mImages = new ArrayList<>();
private Context mContext;
public RecyclerViewAdapter(Context mContext, ArrayList<String> mImageNames, ArrayList<String> mImages) {
this.mImageNames = mImageNames;
this.mImages = mImages;
this.mContext = mContext;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_listitem, parent, false);
ViewHolder holder = new ViewHolder(view);
return holder;
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, final int position) {
Log.d(TAG, "onBindViewHolder: called.");
Glide.with(mContext)
.asBitmap()
.load(mImages.get(position))
.into(holder.image);
holder.title.setText(mImageNames.get(position));
holder.parentLayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.d(TAG, "onClick: clicked on: " + mImageNames.get(position));
// Toast.makeText(mContext, mImageNames.get(position), Toast.LENGTH_SHORT).show();
Intent intent = new Intent(mContext, GalleryActivity.class);
intent.putExtra("image_name", mImageNames.get(position));
intent.putExtra("image_url", mImages.get(position));
mContext.startActivity(intent);
}
});
}
#Override
public int getItemCount() {
return mImageNames.size();
}
public class ViewHolder extends RecyclerView.ViewHolder{
CircleImageView image;
TextView title;
RelativeLayout parentLayout;
public ViewHolder(View itemView) {
super(itemView);
image = itemView.findViewById(R.id.image);
title = itemView.findViewById(R.id.title);
parentLayout = itemView.findViewById(R.id.parent_layout);
}
}
}
Update
Gallery activity:
public class GalleryActivity extends AppCompatActivity {
private static final String TAG = "GalleryActivity";
ListView appVersionsList;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_gallery);
appVersionsList = findViewById(R.id.app_versions);
Log.d(TAG, "onCreate: started.");
getIncommingIntent();
}
private void getIncommingIntent() {
Log.d(TAG, "getIncommingIntent: checking for the incomming intents");
if(getIntent().hasExtra("image_url") && getIntent().hasExtra("image_name")) {
String imageUrl = getIntent().getStringExtra("image_url");
String imageName = getIntent().getStringExtra("image_name");
setImage(imageUrl, imageName);
}
}
public void setImage(String imageUrl, String imageName) {
Log.d(TAG, "setImage: setting the image and name to widgets.");
TextView name = findViewById(R.id.image_description);
name.setText(imageName);
ImageView image = findViewById(R.id.image);
Glide.with(this)
.asBitmap()
.load(imageUrl)
.into(image);
}
}
In you app ClickListener :
ArrayList<String> versionList = adapter.getItem(position).getAppVersions();
and use versionList in ApplicationVersionAdapter
ApplicationVersionAdapter adapter = new ApplicationVersionAdapter(this, R.layout.layout_appversion, versionList);
appVersionsList.setAdapter(adapter);
As you are creating another list for app version so your Adapter need List of String (as your data structure).
Change your ApplicationVersionAdapter
import java.util.ArrayList;
public class ApplicationVersionAdapter extends ArrayAdapter<String> {
private static final String TAG = "ApplicationVersionAdapt";
private Context mContext;
private int mResource;
public ApplicationVersionAdapter(#NonNull Context context, int resource, #NonNull ArrayList<String> objects) {
super(context, resource, objects);
this.mContext = context;
this.mResource = resource;
}
#NonNull
#Override
public View getView(int position, #Nullable View convertView, #NonNull ViewGroup parent) {
String appVersion = getItem(position);
// String appVersion = getItem(position).getImageName();
Log.d("Application version: ", getItem(position));
LayoutInflater inflater = LayoutInflater.from(mContext);
convertView = inflater.inflate(mResource, parent, false);
TextView tvAppVersion = convertView.findViewById(R.id.app_version);
tvAppVersion.setText(appVersion);
return convertView;
}
}
In ApplicationVersionAdapter you are going to List of Application again in getView thats wrong. You have to only care about a specific Application List of version.
I have created a Custom TextView to use Font Awesome support, its working fine when you add the text (unicode ) in layout xml. But if am trying to set the text from my Adapter dynamically using view.setText(), its not applying the font.
FontView class
public class FontView extends TextView {
private static final String TAG = FontView.class.getSimpleName();
//Cache the font load status to improve performance
private static Typeface font;
public FontView(Context context) {
super(context);
setFont(context);
}
public FontView(Context context, AttributeSet attrs) {
super(context, attrs);
setFont(context);
}
public FontView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setFont(context);
}
private void setFont(Context context) {
// prevent exception in Android Studio / ADT interface builder
if (this.isInEditMode()) {
return;
}
//Check for font is already loaded
if(font == null) {
try {
font = Typeface.createFromAsset(context.getAssets(), "fontawesome-webfont.ttf");
Log.d(TAG, "Font awesome loaded");
} catch (RuntimeException e) {
Log.e(TAG, "Font awesome not loaded");
}
}
//Finally set the font
setTypeface(font);
}
}
XML for Layout
<com.domain.app.FontView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textSize="60sp"
android:textAlignment="center"
android:text=""
android:gravity="center"
android:id="#+id/iconView"
android:background="#drawable/oval"
android:padding="10dp"
android:layout_margin="10dp" />
My Adapter
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
IconListHolder viewHolder;
if( convertView == null ) {
LayoutInflater layoutInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = layoutInflater.inflate(R.layout.icon, null);
viewHolder = new IconListHolder(v);
v.setTag(viewHolder);
} else {
viewHolder = (IconListHolder) v.getTag();
}
//Set the text and Icon
viewHolder.textViewIcon.setText(pages.get(position).getIcon());
viewHolder.textViewName.setText(pages.get(position).getTitle());
return v;
}
private class IconListHolder {
public FontView textViewIcon;
public TextView textViewName;
public IconListHolder(View base) {
textViewIcon = (FontView) base.findViewById(R.id.iconView);
textViewName = (TextView) base.findViewById(R.id.iconTextView);
}
}
Please help whats am doing wrong.
After struggling more than 3 hrs. I have found the answer here. It was unicode issue.
Changing Adapter setText() to use Html.fromHtml("").toString() fixed the issue
viewHolder.textViewIcon
.setText(Html.fromHtml(pages.get(position).getIcon()).toString());
Read more here
I hope you guys find it useful.
Could not find an error of your code.
This the custom textView which I'm using. Create font folder inside your assets folder
CustomText.java
import android.content.Context;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.widget.TextView;
public class CustomText extends TextView {
public CustomText(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(attrs);
}
public CustomText(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs);
}
public CustomText(Context context) {
super(context);
init(null);
}
private void init(AttributeSet attrs) {
if (attrs!=null) {
{
Typeface myTypeface = Typeface.createFromAsset(getContext().getAssets(),"fonts/custom_font.ttf");
setTypeface(myTypeface);
}
}
}
}
I have list of title-CheckBox, and i want to have control which one will be checked on default. So I'm trying to get the right view and check it, but for some reason it doesn't work. any idea why?
form_checkbox_item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal" >
<CheckBox
android:id="#+id/checkBox1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="40dp"
android:textColor="#color/background_red"
android:padding="12dp"
/>
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:text="TextView"
android:textColor="#color/background_red"
android:textSize="18sp" />
</LinearLayout>
CheckboxAdapter.java
package com.rgis.datacollection.ui.adapters;
import android.app.Activity;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.TextView;
import com.rgis.datacollection.R;
import java.util.List;
public class CheckboxAdapter extends ArrayAdapter
{
Context context;
List<String> checkboxItems;
public CheckboxAdapter(Context context, List<String> resource)
{
super(context, R.layout.form_checkbox_item ,resource);
this.context = context;
this.checkboxItems = resource;
}
public View getView(int position, View convertView, ViewGroup parent)
{
LayoutInflater inflater = ((Activity)context).getLayoutInflater();
convertView = inflater.inflate(R.layout.form_checkbox_item, parent, false);
TextView textView = (TextView) convertView.findViewById(R.id.textView1);
CheckBox cb = (CheckBox) convertView.findViewById(R.id.checkBox1);
textView.setText(checkboxItems.get(position));
return convertView;
}
}
part of formCheckBox.java
formItem = (LinearLayout) linflater.inflate(R.layout.checkbox_layout, null);
listView = (ListView) formItem.findViewById(R.id.checkboxList);
stringList = dbUtils.getServiceConfigForFixedOptions(attribute.getListValues());
CheckboxAdapter checkboxAdapter = new CheckboxAdapter(context, stringList);
listView.setAdapter(checkboxAdapter);
CheckBox cb = (CheckBox) checkboxAdapter.getView(0, null, listView).findViewById(R.id.checkBox1);
cb.setChecked(true);
I recomend you to implement this way:
Pass a boolean array in the constructor to initialize states.
Register a listener for checkbox state changes to update the states array.
Implement "isChecked" to check if an item is checked at determinated position.
Using "getCount" and "isChecked" you can traverse the list from outside the adapter.
Here is the code:
public class CheckboxAdapter extends ArrayAdapter<String> {
List<String> subcategories;
boolean[] checked;
public SubcategoriesAdapter(Context context, List<String> subcategories, boolean[] checked) {
super(context, android.R.layout.simple_list_item_1);
this.subcategories = subcategories;
this.checked = checked;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = ((Activity)context).getLayoutInflater();
convertView = inflater.inflate(R.layout.form_checkbox_item, parent, false);
TextView textView = (TextView) convertView.findViewById(R.id.textView1);
CheckBox cb = (CheckBox) convertView.findViewById(R.id.checkBox1);
textView.setText(checkboxItems.get(position));
// Set state
cb.setChecked(checked[position]);
// Register listener
cb.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
checked[position] = cb.isChecked();
}
});
return convertView;
}
#Override
public int getCount() {
return subcategories.size();
}
#Override
public DTOSubcategoria getItem(int position) {
return subcategories.get(position);
}
public void selectAll() {
selectAll(true);
notifyDataSetChanged();
}
public void selectNone() {
selectAll(false);
notifyDataSetChanged();
}
void selectAll(boolean selected) {
for (int i = 0; i < checked.length; i++) {
checked[i] = selected;
}
}
public boolean isChecked(int index) {
return checked[index];
}
}
NOTE: Once you fix your adapter, consider modifying it to use the ViewHolder pattern and so improve performance.
One way is having a list of booleans in your adapter which represents the state of every checkbox. You need to init that to false and then with a setCheckbox method change the state of a specific checkbox
public class CheckboxAdapter extends ArrayAdapter
{
Context context;
List<Boolean> checkboxState;
List<String> checkboxItems;
public CheckboxAdapter(Context context, List<String> resource)
{
super(context, R.layout.form_checkbox_item ,resource);
this.context = context;
this.checkboxItems = resource;
this.checkboxState = new ArrayList<Boolean>(Collections.nCopies(resource.size(), true));
}
public View getView(int position, View convertView, ViewGroup parent){
LayoutInflater inflater = ((Activity)context).getLayoutInflater();
convertView = inflater.inflate(R.layout.form_checkbox_item, parent, false);
TextView textView = (TextView) convertView.findViewById(R.id.textView1);
CheckBox cb = (CheckBox) convertView.findViewById(R.id.checkBox1);
textView.setText(checkboxItems.get(position));
cb.setChecked(checkboxState.get(position));
return convertView;
}
This method let you control which checkboxes are actived
void setChecked(boolean state, int position)
{
checkboxState.set(position, state);
}
i want to use Customizing Android ListView Rows by Subclassing in my application but after wending that way i get an error to Import correct class for Item & ItemView my app support old version of android and i'm using android.support for any class.
Notify for import Item:
Notify for import ItemView:
introducing class for inport not correct and i get an error such as setItem.
How to resolve this problem and can be import correct class?
ItemAdapter class:
import java.util.List;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import ir.tsms.wsdl.ReceiveFields;
public class ItemAdapter extends ArrayAdapter<ReceiveFields> {
public ItemAdapter(Context c, List<ReceiveFields> items) {
super(c, 0, items);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ItemView itemView = (ItemView)convertView;
if (null == itemView)
itemView = ItemView.inflate(parent);
itemView.setItem(getItem(position));
return itemView;
}
}
Fragment:
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
ArrayList<ReceiveFields> items = new ArrayList<ReceiveFields>();
for (int i = 0; i < 100; i++) {
String url = String.format("http://www.google.com/image/%d.png", i);
String title = String.format("Item %d", i);
String description = String.format("Description of Item %d", i);
Item item = new Item(url, title, description);
items.add(item);
}
setListAdapter(new ItemAdapter(getActivity(), items));
return super.onCreateView(inflater, container, savedInstanceState);
}
As Mike M says you should be defining the Item and ItemView classes rather then trying to import them. Hence, and this is from your link, you should have two classes. ItemView looks kind of like:
public class ItemView extends RelativeLayout {
private TextView mTitleTextView;
private TextView mDescriptionTextView;
private ImageView mImageView;
public ItemView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
LayoutInflater.from(context).inflate(R.layout.item_view_children, this, true);
setupChildren();
}
public static ItemView inflate(ViewGroup parent) {
ItemView itemView = (ItemView)LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_view, parent, false);
return itemView
}
private void setupChildren() {
mTitleTextView = (TextView) findViewById(R.id.item_titleTextView);
mDescriptionTextView = (TextView) findViewById(R.id.item_descriptionTextView);
mImageView = (ImageView) findViewById(R.id.item_imageView);
}
public void setItem(Item item) {
mTitleTextView.setText(item.getTitle());
mDescriptionTextView.setText(item.getDescription());
// TODO: set up image URL
}
}
And then you would also need an Item class and to set up your layout files. I hope this helps.
The sample code for the tutorial is on github. Here are the key classes I used:
https://github.com/bignerdranch/android-listview-custom-view/tree/master/ListItemViewDemo/src/com/bignerdranch/android/listitemviewdemo
"Item" and "ItemView" are just the names I chose; you might want to use something more specific to your application's domain.
Glad you like the pattern!
how to modify this imageCheckBoxAdapter code in order to maintain status of checkBox when scrolled(that is all the checkboxes which are checked should remain checked even after scrolling. Also the checked variables need to be stored in an array)?
class imageCheckBoxAdapter extends ArrayAdapter<String>
{
private final Context context;
private final ArrayList<String> values;
private final Map< String, SmbFile> obj;
static ArrayList<Boolean> checks=new ArrayList<Boolean>();
public imageCheckBoxAdapter(Context context,ArrayList<String> values,Map< String, SmbFile>obj)
{
super(context, R.layout.row_checkbox, values);
this.context = context;
this.values = values;
this.obj=obj;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View rowView = inflater.inflate(R.layout.row_checkbox, parent, false);
TextView textView = (TextView) rowView.findViewById(R.id.text1_check);
textView.setText(values.get(position));
ImageView imageView = (ImageView) rowView.findViewById(R.id.icon_image_check);
try
{
if((obj.get(values.get(position)).isFile()))
{
imageView.setImageResource(R.drawable.view_file_icon);
}
else
{
imageView.setImageResource(R.drawable.view_folder_icon);
}
}
catch (SmbException e)
{
Toast.makeText(context,"Network error",Toast.LENGTH_SHORT).show();
Log.d("id1", "error1");
e.printStackTrace();
}
return rowView;
}
}
row_checkbox.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="5dp" >
<CheckBox
android:id="#+id/checkBox1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="false" />
<ImageView
android:id="#+id/icon_image_check"
android:layout_width="50px"
android:layout_height="50px"
android:layout_marginLeft="5px"
android:layout_marginRight="20px"
android:layout_marginTop="5px"
android:src="#drawable/view_file_icon" >
</ImageView>
<TextView
android:id="#+id/text1_check"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#+id/label"
android:textSize="30px"
android:typeface="sans">
</TextView>
</LinearLayout>
class imageCheckBoxAdapter extends ArrayAdapter<String> implements View.onClickListener
{
private final Context context;
private final ArrayList<String> values;
private final Map< String, SmbFile> obj;
private ArrayList<Boolean> checks=new ArrayList<Boolean>();
public imageCheckBoxAdapter(Context context,ArrayList<String> values,Map< String, SmbFile>obj)
{
super(context, R.layout.row_checkbox, values);
this.context = context;
this.values = values;
this.obj=obj;
for (int i = 0; i < values.size(); i++) {
checks.add(i, false);
}
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View rowView = inflater.inflate(R.layout.row_checkbox, parent, false);
TextView textView = (TextView) rowView.findViewById(R.id.text1_check);
CheckBox chk = (CheckBox) rowView.findViewById(R.id.checkBox1);
textView.setText(values.get(position));
ImageView imageView = (ImageView) rowView.findViewById(R.id.icon_image_check);
try
{
if((obj.get(values.get(position)).isFile()))
{
imageView.setImageResource(R.drawable.view_file_icon);
}
else
{
imageView.setImageResource(R.drawable.view_folder_icon);
}
}
catch (SmbException e)
{
Toast.makeText(context,"Network error",Toast.LENGTH_SHORT).show();
Log.d("id1", "error1");
e.printStackTrace();
}
chk.setTag(Integer.valueOf(position));
// Set a listener for the checkbox
chk.setOnClickListener(this);
//Sets the state of CB, since we have the list of checked CB
chk.setChecked(checks.get(position));
return rowView;
}
#Override
public void onClick(View view) {
Integer index = (Integer)view.getTag();
boolean state = checks.get(index.intValue());
checks.set(index.intValue(), !state);
}
}
I think your need to store value in an array. For each checkBox, you set a changeListener to store the checkBox associated.
I recently read, not sure where already, a similar case someone asked about.
If I understand correctly, this may be because the CheckBox control is not databound in the DataRepeaterItem, and when scrolling the checkboxes lose their state.
You can try using Viewstate to maintain checked value. I'll try finding that post, it seemed informative.
I think you can save the position of the checkbox in the list by using the View.setTag method
make a reference of your checkbox in the getView like this:
CheckBox chk = (CheckBox) rowView.findViewById(R.id.checkBox1);
Since CheckBoxes are indirect subclasses of View, it also has an attribute View.setTag like this:
chk.setTag(Integer.valueOf(position));
Then set an OnCheckedChangeListener to your chk like:
chk.setOnCheckedChangeListener(new OnCheckedChangeListener {
public void onCheckedChanged(CompoundButton buttonView, boolean state) {
Integer int = (Integer)buttonView.getTag();
checks.set(int.intValue(), !boolean)
}
});
Since the boolean arraylist size is same to the values size, the specified position corresponds the exact location of the checkbox
Then add this snippet to your getView method:
if (checks.get(position)) {
chk.setChecked(checks.get(position));
// do some stuff if wanted..
} else {
chk.setChecked(checks.get(position));
// do some stuff if wanted..
}
We did the snippet because when listview is scrolled upward or downward getView is called for the unseen row item. And to update the row item if already checked or not.