MVVMCross Data Binding not working - xamarin

I have custom object in my ViewModel.
public MyObject PropertyName
{
get { return _propertyName; }
set
{
_propertyName = value;
RaisePropertyChanged(() => PropertyName);
}
}
I want to bind only one of its member to textview in my droid view. Found this link:
Bind data of custom object to TextView in MvvmCross
And I am doing exactly like this. local:MvxBind = "Text Myobject.ItsMember"
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:text="LabelCaption" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:textColor="#android:color/white"
local:MvxBind="Text Myobject.ItsMember" />
</RelativeLayout>
</LinearLayout>
</ScrollView>
</LinearLayout>
Checked the casing etc. but binding isn't working and I cannot see the string value appearing on the screen while I can print it in the debug window.
Any clues where I may be going wrong?

I cannot reproduce your issue on my end.
I've tried with:
public class MyViewModel : MvxViewModel
{
private MyModel _model; // this is a class member variable or class member field
public MyModel Model // this is a class member property
{
get => _model;
set => SetProperty(ref _model, value);
}
public MyViewModel()
{
Model = new MyModel { Name = "Herp" };
}
}
public class MyModel : MvxNotifyPropertyChanged
{
private string _name;
public string Name
{
get => _name;
set => SetProperty(ref _name, value);
}
}
Then given that MyViewModel is DataContext I bind using:
local:MvxBind="Text Model.Name"
Works just fine.

You can't bind to a type. You need to bind to an instance of the type. In order for the binding to work the way you have it set in the AXML you need something like
public class MyType
{
private string _ItsMember;
public string ItsMember
{
get
{
return _ItsMember;
}
set
{
_ItsMember = value;
RaisePropertyChanged (()=>ItsMember);
}
}
}
private MyType _MyObject;
public MyType MyObject
{
get
{
return _MyObject;
}
set
{
_MyObject = value;
RaisePropertyChanged(()=>MyObject);
}
}
This arrangement will allow MyObject.ItsMember to resolve to a string property value. If your property is not a string value, you will have to implement a converter which is a whole 'nother subject.

Related

How to wire up MvxRecyclerView Item's actions to ViewModel

I have a MvxRecyclerView which has the following axml file:
<?xml version="1.0" encoding="utf-8"?>
<MvvmCross.Droid.Support.V7.RecyclerView.MvxRecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:MvxItemTemplate="#layout/item_detail"
app:MvxBind="ItemsSource Items" />
Correspodning ViewModel is defined like this:
public class ItemsViewModel : MvxViewModel
{
private ObservableCollection<Models.Item> _items;
public ObservableCollection<Models.Item> Items
{
get { return _items; }
set
{
_items = value;
RaisePropertyChanged(() => Items);
}
}
public MvxCommand CommandToBeInvokedFromItem
{
get
{
return new MvxCommand(async () =>
{
await ...;
});
}
}
...
}
My item_detail axml is defined like this:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="24dp"
local:MvxBind="Text Name" />
<ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/ic_delete_forever_black_24dp"
local:MvxBind="Click CommandToBeInvokedFromItem"/>
</LinearLayout>
And Model.Item is defined like this:
public class Item
{
public string Name { get; set; }
}
First TextView binds to Item's name property which works great. But I want the ImageButton to bind to a Command on the ViewModel to which MvxRecylerView is bound rather than to a property of the Item. Item is just a Model and not a ViewModel. How do I accomplish that?
If you need the command to be called on the click of an item in the MvxRecycler (i.e. the entire cell), the binding is relatively simple. Just change the value of MvxBind on the MvxRecyclerView from ItemsSource Items to ItemsSource Items; ItemClick CommandToBeInvokedFromItem. CommandToBeInvokedFromItem would then need to be modified to accept Item as a type parameter, which would look like this:
public MvxCommand<Models.Item> CommandToBeInvokedFromItem
{
get
{
return new MvxCommand<Models.Item>(async () =>
{
await ...;
});
}
}
If the command needs to be raised specifically by clicking on the ImageButton, then the easiest method would be to move CommandToBeInvokedFromItem to Item, and to have Item inherit MvxViewModel, or at least implement INotifyPropertyChanged.
Hand the command over to the Item when you create it in yourItemsViewModel.
public class Item
{
public string Name { get; set; }
public MvxCommand CommandToBeInvokedFromItem {get;}
public Item(MvxCommand clickCommand)
{
CommandToBeInvokedFromItem = clickCommand;
}
}

MvvmCross MvxListView ItemClick Enabled Based on property

So I have a MvxListView
<Mvx.MvxListView
android:id="#+id/receptionsListView"
android:divider="#drawable/divider"
android:scrollbars="vertical"
android:choiceMode="singleChoice"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="left|start"
local:MvxItemTemplate="#layout/item_supplier"
local:MvxBind="ItemsSource ReceptionSuppliersList; ItemClick SelectReceptionCommand;" />
I want to enabled/disabled some Items based on a value from model in the list. Something like
local:MvxBind="ItemsSource ReceptionSuppliersList; ItemClick SelectReceptionCommand; Enabled ReceptionSuppliersList.IsValid" />
From what I've tested this just disabled all my list items because there is no such property ReceptionSuppliersList.IsValid ( it's ReceptionSuppliersList[i].IsValid ). How can I achive this.
I also tried to add the Enabled Property on item_supplier like this
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="0dp"
style="#style/ExtendProTheme.ReceptionItem"
local:MvxBind="Enabled IsValid" >
But it still doesn't work.
Any ideas how can i disable some of the item from my list based on a property?
PS :
My items look like this
public string Username { get; set; }
public string DeviceId { get; set; }
public bool IsValid { get; set; }
You could create a custom adapter to handle the enabling/disabling of list items. You would just need to cast the Adapters ItemsSource to your ViewModels
ReceptionSuppliersList type in the IsEnabled override.
public class CustomAdapter : MvxAdapter
{
public CustomAdapter(Context context)
: base(context)
{
}
public CustomAdapter(Context context, IMvxAndroidBindingContext bindingContext)
: base(context, bindingContext)
{
}
protected CustomAdapter(IntPtr javaReference, JniHandleOwnership transfer) :
base(javaReference, transfer)
{
}
public override bool IsEnabled(int position)
{
var items = ItemsSource as List<TestModel>;
return items[position].IsValid;
}
}
Assign adapter to your MvxListView:
var receptionsListView = FindViewById<MvxListView>(Resource.Id.receptionsListView);
receptionsListView.Adapter = new CustomAdapter(this, BindingContext as IMvxAndroidBindingContext);
That's not a real problem-solve, but it should work for your case:
Add gray overlay on the item to make it look like it's not enabled.
Check whether item is enabled on the method handler for SelectReceptionCommand.
private void OnSelectReceptionCommandExecuted(Reception item)
{
if (!reception.IsEnabled)
{
return;
}
// your code here
}

How to implement Recycler View in MvvmCross using MvxRecyclerView

In MvvmCross, I have an android listview within an activity that works.
I read somewhere that changing the listView to a recyclerView is as simple as changing MvxListView to MvxRecyclerView in my layout .axml file. Trying that gives me the following runtime exception:
Android.Views.InflateException: Binary XML file line #1: Binary XML file line #1: Error inflating class Mvx.MvxRecyclerView
Is there anything that I have to do differently in the code behind or view model when using MvxRecyclerView? Below is my code.
Layout files:
Main.axml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Mvx.MvxRecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical"
android:id="#+id/words_listview"
local:MvxItemTemplate="#layout/words_listview_row"
local:MvxBind="ItemsSource Words" />
</LinearLayout>
words_listview_row.axml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:p1="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res-auto"
p1:minWidth="25px"
p1:minHeight="25px"
p1:layout_width="match_parent"
p1:layout_height="match_parent"
p1:id="#+id/relativeLayout1"
p1:background="#FFFFFF">
<TextView
p1:text="Word name"
p1:layout_width="wrap_content"
p1:layout_height="wrap_content"
p1:id="#+id/headingTextView"
p1:width="325dp"
p1:textColor="#000000"
p1:layout_alignParentLeft="true"
p1:textSize="18sp"
p1:paddingLeft="20dp"
p1:paddingTop="15dp"
local:MvxBind="Text Name" />
<TextView
p1:text="Word meaning"
p1:layout_width="match_parent"
p1:layout_height="wrap_content"
p1:layout_below="#id/headingTextView"
p1:id="#+id/detailTextView"
p1:textColor="#8f949a"
p1:layout_alignParentLeft="true"
p1:textSize="16sp"
p1:paddingLeft="20dp"
p1:paddingRight="20dp"
p1:paddingBottom="15dp"
local:MvxBind="Text Meaning" />
</RelativeLayout>
WordViewModel.cs
using MvvmCross.Core.ViewModels;
using VocabBuilder.Core.Models;
using VocabBuilder.Core.Services.Interfaces;
namespace VocabBuilder.Core.ViewModels
{
public class WordViewModel : MvxViewModel
{
private IWordService _wordService;
public MvxObservableCollection<Word> Words { get; set; }
public WordViewModel(IWordService wordService)
{
Words = new MvxObservableCollection<Word>();
_wordService = wordService;
Words.ReplaceWith(_wordService.GetAllWords());
}
}
}
Codebehind/ WordView.cs
using Android.App;
using Android.OS;
using MvvmCross.Droid.Views;
using VocabBuilder.Core.ViewModels;
namespace VocabBuilder.UI.Droid.Views
{
[Activity(Label="Vocab Builder", MainLauncher=true)]
public class WordView : MvxActivity<WordViewModel>
{
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.Main);
}
}
}
Thanks.
EDIT:
Here is my Setup.cs file:
using Android.Content;
using MvvmCross.Core.ViewModels;
using MvvmCross.Droid.Platform;
namespace VocabBuilder.UI.Droid
{
public class Setup : MvxAndroidSetup
{
public Setup(Context applicationContext) : base(applicationContext)
{
}
protected override IMvxApplication CreateApp()
{
return new Core.App();
}
}
}
OK, I got RecyclerView to work easily after replacing MvxListView with MvxRecyclerView. Not sure what the particular problem with your implementation is but i will give you the tidbits of mine and you can try it all out.
My RecyclerView lives in a Fragment inheriting from MvxFragment - a bit different than yours but should not be the determining factor. Here are some Fragment snippets:
public class ListsFragment : MvxFragment<ListsViewModel>
{
...
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
base.OnCreateView(inflater, container, savedInstanceState);
var view = this.BindingInflate(Resource.Layout.fragment_listsfragment, null);
return view;
}
...
}
Here is the axml for fragment_listsfragment:
<?xml version="1.0" encoding="utf-8"?>
<MvvmCross.Droid.Support.V7.RecyclerView.MvxRecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:MvxItemTemplate="#layout/item_list"
app:MvxBind="ItemsSource Lists; ItemClick ShowListItemsCommand" />
I do see a bit of difference in your ViewModel implementation - mine is like this:
public class ListsViewModel : BaseViewModel
{
...
private readonly IListService _listService;
private ObservableCollection<Models.List> _lists;
public ObservableCollection<Models.List> Lists
{
get { return _lists; }
set
{
_lists = value;
RaisePropertyChanged(() => Lists);
}
}
public MvxCommand<Models.List> ShowListItemsCommand
{
get
{
return new MvxCommand<Models.List>(selectedList =>
{
ShowViewModel<ListItemsViewModel>
(new { listId = selectedList.Id });
});
}
}
...
public override async void Start()
{
base.Start();
await InitializeAsync();
}
protected override async Task InitializeAsync()
{
await _listService.InitializeAsync();
Lists = (await _listService.GetListsAsync())
.ToObservableCollection();
}
}
Hope this helps.

RecyclerView item dynamic Height micro stutter

I use an EndlessAdapter with a RecyclerView to fetch and load few hundred items from server.
Glide takes care to load the images for each row.
If user scrolls slowly, everything works fine, but when he flings, there are some micro stuttering in scrolling.
I think that this happens due to different image height for each row, but I don't know how to eliminate it.
My adapter code:
public final class ImagesAdapter extends EndlessAdapter<Image, ImagesAdapter.imageHolder> {
#NonNull
private static Fragment mFragment;
private OnItemClickListener onItemClickListener;
private static int mScreenWidth;
private int layoutStyle;
public ImagesAdapter(#NonNull Fragment fragment, List<Image> images, int layoutStyle) {
super(fragment.getActivity(), images == null ? new ArrayList<Image>() : images);
mFragment = fragment;
setHasStableIds(true);
mScreenWidth = fragment.getResources().getDisplayMetrics().widthPixels;
this.layoutStyle = layoutStyle;
}
public void changeLayout(int layoutStyle){
this.layoutStyle = layoutStyle;
}
public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
this.onItemClickListener = onItemClickListener;
}
#Override
public long getItemId(int position) {
return (!isLoadMore(position)) ? mItems.get(position).getId() : -1;
}
#Override
protected imageHolder onCreateItemHolder(ViewGroup parent, int viewType) {
final imageHolder holder;
switch (layoutStyle) {
case 0:
default:
holder = new imageHolder(mInflater.inflate(R.layout.item_image_enhanced_optim, parent, false));
break;
case 1:
holder = new imageHolder(mInflater.inflate(R.layout.item_image, parent, false));
break;
}
return holder;
}
#Override
protected ProgressViewHolder onCreateItemProgressBarHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.progressbar_item, parent, false);
return new ProgressViewHolder(v);
}
#Override
public void onViewRecycled(RecyclerView.ViewHolder holder) {
super.onViewRecycled(holder);
if (holder instanceof ProgressViewHolder) {
((ProgressViewHolder) holder).progressBar.stop();
Timber.d("Stopped progressbar");
}
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (holder.getItemViewType() == VIEW_TYPE_ITEM) {
((imageHolder) holder).bind(mItems.get(position));
} else {
((ProgressViewHolder) holder).start();
}
}
public void shuffle(List<Image> images) {
mItems.clear();
this.mItems.addAll(images);
notifyDataSetChanged();
}
final class imageHolder extends RecyclerView.ViewHolder {
#Bind(R.id.item_image_content)
FrameLayout container;
#Bind(R.id.item_image_img)
ImageView mImageView;
#Bind(R.id.item_image_name)
TextView imageName;
#Bind(R.id.item_author_name)
TextView imageAuthorName;
#Bind(R.id.item_author_image)
CircleImageView userImage;
#Bind(R.id.item_image_date)
TextView imageDate;
#Bind(R.id.item_image_comments)
TextView comments;
#Bind(R.id.item_view_on_map)
LinearLayout viewOnMap;
#Bind(R.id.item_view_share)
LinearLayout share;
#Bind(R.id.moreView)
LinearLayout moreView;
#Bind(R.id.progress_image)
LoadingView loadingView;
public imageHolder(View view) {
super(view);
ButterKnife.bind(this, view);
}
public void bind(#NonNull final Image image) {
container.setOnClickListener(new onImageClickListener(getAdapterPosition()));
userImage.setOnClickListener(new onAuthorClickListener(userImage, getAdapterPosition()));
viewOnMap.setOnClickListener(new onViewOnMapClickListener(getAdapterPosition()));
share.setOnClickListener(new onShareClickListener(getAdapterPosition()));
moreView.setOnClickListener(new onMoreClickListener(getAdapterPosition()));
loadingView.setVisibility(View.VISIBLE);
imageName.setText(image.getCombinedTitle());
imageAuthorName.setText(image.getAuthor());
imageDate.setText(image.getReadableDate());
comments.setText(image.getComments());
if(!loadingView.isCircling())
loadingView.start();
Glide.with(mFragment)
.load(image.getImageSrc(mScreenWidth))
.crossFade()
.override(mScreenWidth, (int) ((float) mScreenWidth / image.getRatio()))
.listener(new RequestListener<String, GlideDrawable>() {
#Override
public boolean onException(Exception e, String model, Target<GlideDrawable> target, boolean isFirstResource) {
return false;
}
#Override
public boolean onResourceReady(GlideDrawable resource, String model, Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) {
loadingView.stop();
loadingView.setVisibility(View.GONE);
return false;
}
})
.into(mImageView);
}
}
and the row item
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/main_container"
android:layout_marginBottom="5dp"
android:layout_marginLeft="0dp"
android:layout_marginRight="0dp"
android:layout_marginTop="5dp"
app:cardCornerRadius="0dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#color/white">
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/light_gray"
android:orientation="vertical">
<ImageView
android:id="#+id/item_image_img"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
tools:src="#drawable/header"
android:contentDescription="#string/img_content"
android:scaleType="fitXY" />
<FrameLayout
android:id="#+id/item_image_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true"
android:foreground="?selectableItemBackgroundBorderless"
android:orientation="vertical" />
</FrameLayout>
<include layout="#layout/item_image_header"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:gravity="center_vertical"
android:layout_marginLeft="47dp"
android:visibility="visible"
android:paddingRight="10dp"
android:layout_marginBottom="5dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
tools:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:paddingBottom="5dp"
android:paddingTop="5dp"
android:gravity="center_vertical">
<ImageView
android:layout_width="10dp"
android:layout_height="10dp"
android:layout_marginRight="3dp"
android:contentDescription="#string/descr" />
<TextView
android:id="#+id/item_image_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="end"
android:lines="1"
android:textColor="#color/colorPrimary"
android:textSize="15.0sp"
android:layout_gravity="center_vertical" />
</LinearLayout>
<TextView
android:id="#+id/item_image_comments"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:ellipsize="end"
android:maxLines="4"
tools:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:textColor="#android:color/primary_text_light_nodisable"
android:textSize="13.0sp"
android:layout_marginBottom="10dp" />
</LinearLayout>
<View
android:id="#+id/divider"
android:layout_width="match_parent"
android:background="#drawable/divider_shape"
android:layout_height="0.5dp" />
<include layout="#layout/item_image_bottom_buttons"/>
</LinearLayout>
Glide stop loading Images When you scroll list very fast it is done to improve the speed of Scrolling and avoiding any jitter
If you want to show images to your user I suggest you to use Picasso.
https://github.com/square/picasso
However Picasso is not good in caching the Images or has a limited Caching
or Either way u use placeHolder to represent the Image.
Edit
Heads up u can do it easily with Glide
Glide.with(getActivity())
.load("http://www.mediafile.com/12364f")
.placeholder(R.drawable.circle_placeholder_drawable)//this will show this image till your image is not fully loaded
.error(R.drawable.error_drawable)// if there is a problem in loading image an error image would be loaded instead
.into(holder.mFileTransferCircleImageView);

The child views of the my parent ViewGroup remains unchanged and gets displayed in my new inflated layout at the bottom

Inflation using Array Adapter - The inflated layout does not fill my full screen.
The views present in the parent View Group get displayed at the bottom of my newly inflated layout. The inflation is not fitting full screen and causing display issues as in the image. Code is working fine but i am having problem with my Display. Please suggest possible solution. The parent XML is also an inflated layout list(Array Adapter).
Note
The layout is properly inflated by setting attachRoot=false
(Inflater.inflate(R.layout.chapterlayout, parent, false)).
Cannot process ViewGroup from ArrayAdapter , so unable to remove the parent views.
INFLATED XML LAYOUT
<?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:background="#drawable/my_background"
android:orientation="vertical"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:weightSum="100" >
<TextView
android:id="#+id/ENo"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="90"
android:text="1."
android:textColor="#0000FF"
android:textSize="15sp"
android:textStyle="bold" >
</TextView>
<TextView
android:id="#+id/EA"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="10"
android:paddingBottom="5sp"
android:text="My Text"
android:textColor="#0000FF"
android:textSize="15sp"
android:textStyle="bold" >
</TextView>
</LinearLayout>
<TextView
android:id="#+id/EE"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="My Text"
android:textColor="#0000FF"
android:textSize="15sp"
android:textStyle="bold" >
</TextView>
</LinearLayout>
PARENT 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="fill_parent"
android:background="#drawable/my_background">
<TextView
android:id="#+id/txt"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="#+id/label"
android:textSize="15sp"
android:textColor="#0000FF"
android:textStyle="bold"
android:background="#drawable/my_background">
</TextView>
</LinearLayout>
JAVA CODE
public class MyChapterAdapter extends ArrayAdapter<String> {
private final Context context;
private final String[] values;
public MyChapterAdapter(Context context, String[] values) {
super (context, R.layout.main, values);
this.context = context;
this.values = values;
}
static class ViewHolder {
TextView ENo;
TextView EA;
TextView EE;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
LayoutInflater li = (LayoutInflater)
getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = li.inflate(R.layout.chapterlayout, parent, false);
holder = new ViewHolder();
holder.ENo = (TextView) convertView.findViewById(R.id.ENo);
holder.EA = (TextView) convertView.findViewById(R.id.EA);
holder.EE = (TextView) convertView.findViewById(R.id.EE);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
reDesignLayout(position, holder);
return convertView;
}
private void reDesignLayout(int position, ViewHolder h) {
// TODO Auto-generated method stub
String chapSplit[] =values[position].split("##");
h.ENo.setText(chapSplit[0]+". ");
h.EA.setText(chapSplit[1]);
h.EE.setText(chapSplit[2]);
}
}

Resources