ListView with a ListView header - java

I have a problem with adding a listview as a header in my listview (go go redundancy). The code is working, however only the first item shows up in the header. The body looks fine.
listView = (ListView) findViewById(R.id.default_list_view);
header = (ListView) getLayoutInflater().inflate(R.layout.savings_overview_header_list, null, false);
HeaderAdapter hAdapter = new HeaderAdapter(getLayoutInflater());
hAdapter.addItem("1");
hAdapter.addItem("2");
hAdapter.addItem("3");
header.setAdapter(hAdapter);
for (Policy p : saving.getPolicies()) {
adapter.addItem(p);
}
listView.addHeaderView(header);
listView.setAdapter(adapter);
headerView:
<ListView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/default_list_view"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:cacheColorHint="#00000000"
android:divider="#drawable/list_divider"
android:dividerHeight="2px"
android:fadingEdge="none"
android:fitsSystemWindows="true"
android:footerDividersEnabled="false"
android:headerDividersEnabled="false"
android:listSelector="#drawable/list_item_background_selected"
>
</ListView>
I have tried wrapping the ListView in a vertical LinearLayout but no cigar there either :(
hAdapter
private static class HeaderAdapter extends BaseAdapter {
private final LayoutInflater inflater;
protected ArrayList<String> data = new ArrayList<String>();
public HeaderAdapter(LayoutInflater inflater) {
this.inflater = inflater;
}
public void addItem(String s) {
data.add(s);
}
public View getView(int position, View convertView, ViewGroup parent) {
final PolicyViewHolder holder;
if (convertView == null) {
convertView = inflater.inflate(R.layout.savings_overview_header_item, parent, false);
holder = new PolicyViewHolder();
holder.header = (TextView) convertView.findViewById(R.id.list_item_header);
holder.subHeader = (TextView) convertView.findViewById(R.id.list_item_subheader);
holder.img = (ImageView) convertView.findViewById(R.id.list_item_img);
convertView.setTag(holder);
} else {
holder = (PolicyViewHolder) convertView.getTag();
}
String s = data.get(position);
holder.header.setText(s);
holder.subHeader.setText(s);
holder.img.setImageResId(R.drawable.test);
return convertView;
}
public int getCount() {
return data.size();
}
public Object getItem(int position) {
return data.get(position);
}
public long getItemId(int position) {
return position;
}
private static class PolicyViewHolder {
TextView header;
TextView subHeader;
ImageView img;
}
}
header_item
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="10dp"
android:paddingRight="10dp" >
<ImageView
android:id="#+id/list_item_img"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:src="#drawable/ic_launcher"/>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginRight="10dp"
android:layout_marginLeft="5dp"
android:layout_toLeftOf="#+id/list_item_value"
android:layout_toRightOf="#+id/header_image"
android:orientation="vertical" >
<TextView
android:id="#+id/list_item_header"
style="#style/header_list_header"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/list_item_subheader"
style="#style/list_header_sub_header"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="sub header" />
</LinearLayout>
</RelativeLayout>
i have tried to wrap a linearlayout="vertical" around this one as well

You have to tell the parent view how to stack your elememnts. This is necessary for parents like a LinearLayout. If you're going to have such an adapter, you need to have a parent to contain these things, UNLESS its a single view.
Update
Whenever you want to do processing with the views in a ListView you
need to create a custom adapter that will handle your logic
implementation and pass that information to the views as necessary.
A custom adater would inflate the views piece by piece, this can be
dynamic of fixed.

I suspect that your problem relates to Android simply not knowing how to handle the two levels of "scrollability" this design implies. Think about it - If the user drags over the header, how is Android supposed to know whether they mean to scroll the outer list or the list within the header? I once recall Romain Guy making the same point about placing ListViews inside ScrollViews, it's slightly meaningless.
What's probably happening is that Android makes the header big enough to simply display a single header list item and it assumes any dragging gesture by the user should apply to the outer list.
Generally, I think what you've described sounds like a bad design choice and you need to take a step back.
What functionally do you want this UI to do?
If it's simply that you want to display two sets of content within a single list, then this is a problem you need to solve within the ListAdapter implementation you're using. e.g. Take a look Jeff Sharkey's blog post on his SeparatedListAdapter.

Make a LinearLayout with vertical orientation and add both ListViews there. That should fix your hiccup.
Cheers.

Related

Android: Why is onItemClick for my ListView using ArrayAdapter not working?

I have a ListView made up of a LinearLayout and some elements within. It's driven by a custom Adapter that extends ArrayAdapter>. For some reason it's not getting called when I click on of of the displayed items. Nothing happens in logcat. No error, no Log, nothing.
I've read a number of similar questions, and tried to implement the solutions, but that doesn't seem to be my issue. I tried onItemClickListener not firing on custom ArrayAdapter and Listview onitemclick listener is not working and OnItemClick not responding to clicks
Here's my activity code:
ratingAdapter = new RatingAdapter(this, RatingRecord);
ratingListView = (ListView) findViewById(R.id.ratingsListView);
ratingListView.setAdapter(ratingAdapter);
ratingListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
Log.d("Ratings update", "Clicked button for " + RatingRecord.get(i).get(1));
RateRestaurant(RatingRecord.get(i));
}
});
Here's my item xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="50dp"
android:orientation="horizontal"
android:clickable="true"
android:id="#+id/ratings_row"
style="#android:style/Widget.Button"
android:descendantFocusability="blocksDescendants"
android:focusable="true">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:textSize="16sp"
android:layout_weight="2"
android:id="#+id/rating_name"
android:focusable="false"/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:adjustViewBounds="true"
android:paddingRight="5dp"
android:id="#+id/rating_icon"
android:focusable="false"/>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:textSize="16sp"
android:layout_weight="1"
android:id="#+id/rating_date"
android:gravity="center_horizontal"
android:focusable="false"/>
</LinearLayout>
Here's the ListView layout from the main activity:
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="10dp"
android:paddingBottom="10dp"
android:id="#+id/ratingsListView"/>
Here's the meat of the adapter RatingAdapter:
public RatingAdapter(Context context, ArrayList<ArrayList<String>> inValues) {
super(context, R.layout.ratings_row, inValues);
this.context = context;
ratingList = CsvUtil.fromCsvTable(context.getString(R.string.Ratings_OptionsList));
}
private ViewHolder(View c, Integer n, Integer i, Integer d) {
NameView = (TextView)c.findViewById(n);
IconView = (ImageView)c.findViewById(i);
DateView = (TextView)c.findViewById(d);
}
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// Get the data item for this position
ArrayList<String> record = getItem(position);
// Check if an existing view is being reused, otherwise inflate the view
ViewHolder vh;
if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.ratings_row, parent, false);
vh = new ViewHolder(convertView,R.id.rating_name,R.id.rating_icon,R.id.rating_date);
convertView.setTag(vh);
} else {
vh = (ViewHolder)convertView.getTag();
}
// Lots of data calculation and populating ViewHolder elements
return convertView;
}
Nothing happens. Like I said, no log or event or error. What have I done wrong?
set on click on your convertview in adapter getView() method.
convertView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.d("Ratings update", "Clicked button for " + RatingRecord.get(i).get(1));
RateRestaurant(RatingRecord.get(i));
}
}
Answer provided by Haresh in the comments.
"please try to remove this line style="#android:style/Widget.Button" from your list item layout"
I used the style Widget.Button to give me the look of a button though the ListView already provided the click through functionality. However the style did more than change the look. It also overrode the clicking function. To get the effect I wanted without the side effects, I just set the background using:
android:background="#android:drawable/btn_default"

nadavfima google cards library data not displaying

I am making an application which displays weather information. To display the weather, i am using the nadavfima google cards ui library. But, when i try to set the textviews in my layout for the card, it does not display even after refreshing in the app. All it displays is the hardcoded values i set in the xml file.
mCards = (CardUI) root.findViewById(R.id.nowCards);
mCards.setSwipeable(false);
// add cards
// add overview card
mCards.addCard(new NowOverviewCard());
mCards.addStack(new CardStack());
// add temperature
mCards.addCard(new SimpleTempCard(getActivity()));
mCards.addStack(new CardStack());
// add detailed values
SimpleValueCard pressure = new SimpleValueCard(getActivity());
mCards.addCard(pressure);
mCards.refresh();
layout view
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="15dp" >
<TextView
android:id="#+id/simpleCardHead"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:fontFamily="sans-serif-thin"
android:text="Humidity"
android:textAppearance="?android:attr/textAppearanceLarge" />
<TextView
android:id="#+id/simpleCardValue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="#+id/simpleCardHead"
android:layout_alignBottom="#+id/simpleCardHead"
android:layout_marginLeft="35dp"
android:layout_toRightOf="#+id/simpleCardHead"
android:fontFamily="sans-serif-thin"
android:text="75%"
android:textAppearance="?android:attr/textAppearanceLarge" />
</RelativeLayout>
My Card view
public class SimpleValueCard extends Card {
View card;
private Context ctx;
public SimpleValueCard( Context ctx) {
this.ctx = ctx;
}
#Override
public View getCardContent(Context context) {
return getViewFromContext(context);
}
#Override
public boolean convert(View convertCardView) {
getViewFromContext(ctx);
TextView header = (TextView) convertCardView
.findViewById(R.id.simpleCardHead);
TextView value = (TextView) convertCardView
.findViewById(R.id.simpleCardValue);
if (header == null || value == null) {
} else {
header.setText("Pressure");
value.setText("84");
}
return true;
}
private View getViewFromContext(Context context) {
LayoutInflater mInflater = (LayoutInflater) context
.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
card = mInflater.inflate(R.layout.card_simple_value, null);
return card;
}
}
The problem is you are calling getViewFromContext(ctx); which return view object but unfortunately you are not using/saving that view object in your convert(View convertCardView).
So you need to store that returned view object & then you should use it in your convert(View convertCardView). It is just like custom listview baseadapter. You need that view object with the help of it you can set your textviews. Because here you are inflating but not exactly using that view object thatswhy its showing static values.
Do above thing, it will surely solve your problem.
Refer Android Custom ListView + BaseAdapter

Android: set LinearLayout to be a value in a Listview

I have a ListView, titled myListView, that I would like to populate with 3 LinearLayout elements, titled layout1.xml, layout2.xml, and layout3.xml. All 3 LinearLayout elements are very similar; here is one of them:
<?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="horizontal" >
<TextView
android:layout_width="0dip"
android:layout_weight="1"
android:layout_height="wrap_content"
android:text="Los Angeles" />
<TextView
android:layout_width="0dip"
android:layout_weight="1"
android:layout_height="wrap_content"
android:text="California" />
</LinearLayout>
My goal is to populate a the ListView (myListView) with these three LinearLayout elements. Does anyone know how I would go about doing this?
First of all, if all three linear layouts are alike, I suggest you to only use one.
Anyway, you have to use a custom adapter for your ListView. You create a class that extends ArrayAdapter for example. If you are not familiar with custom adapters, I suggest you take a look here.
In your getView method, you practically have to inflate a different *.xml, depending on your cell position. Thus:
#Override
puclic View getView (int position, View view, ViewGroup parent) {
LayoutInflater inflater = context.getLayoutInflater();
switch (position) {
case 0: view = inflater.inflate(R.layout.my_layout_1, null, true);
//rest of my code
break;
case 1: view = inflater.inflate(R.layout.my_layout_2, null, true);
//rest of my code
break;
case 2: view = inflater.inflate(R.layout.my_layout_3, null, true);
//rest of my code
break;
default: break;
//rest of my code
return view;
}
As DDsix points out, you really should be using one layout that can handle whatever data you want, and then populate the fields using an adapter. If I had to guess, I'd bet the only difference between your layouts is the text for the city and state.
The documentation explains how to do this very well: http://developer.android.com/guide/topics/ui/layout/listview.html
Basically, you should create a private List<Location> mLocations; variable to hold your locations (Location would be a simple class you define with strings to hold city and state). Then, you can use the following in your adapter.
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
LayoutInflater inflater = context.getLayoutInflater();
View view = inflater.inflate(R.layout.my_layout_1, parent);
Location location = mLocationList.get(position);
TextView cityView = view.findViewById(R.id.city_view);
TextView stateView = view.findViewById(R.id.state_view);
cityView.setText(location.getCity());
cityView.setText(location.getState());
return view;
}

ListView adapter screws up item heights

I have a custom BaseAdapter used for a ListView. The usual layout of a row looks like on the first picture.
Gallery is here
But the list can also have items whose second line's string is empty, like on the second picture, and if that second line's string has a length equal to 0, the second line's view's setVisibility(View.GONE) method is called.
And when the list is filled with items so it's neccessary to scroll to see the most-bottom items, and you scroll down and there is an item with only one line, and you scroll back to top, some of the two-line items can lose their second line, like on the third picture.
A simillar thing happens when an item is deleted from the list - the item going on its place gets the height of the deleted one - like on the fourth picture (forget the colored bar).
So it seems that the adapter thinks the "Cookies" item is the same as the "Something" item... or something.
Why does it happen? How can i fix that?
Another gallery to show exactly what happens
Adapter code:
public class CounterItemAdapter extends BaseAdapter{
private Activity activity;
private ArrayList<CounterItem> data;
private SQLiteOpenHelper helper;
private static LayoutInflater inflater = null;
public CounterItemAdapter(Activity activity, ArrayList<CounterItem> data, SQLiteOpenHelper helper) {
this.activity = activity;
this.data = data;
this.helper = helper;
inflater = (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public int getCount() {
return data.size();
}
#Override
public CounterItem getItem(int position) {
return data.get(position);
}
#Override
public long getItemId(int position) {
return getItem(position).getId();
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
if(convertView == null)
view = inflater.inflate(R.layout.counter_list_item, null);
TextView nameView = (TextView)view.findViewById(R.id.nameView);
TextView descView = (TextView)view.findViewById(R.id.descView);
final TextView countView = (TextView)view.findViewById(R.id.countView);
ImageButton plusButton = (ImageButton)view.findViewById(R.id.plusButton);
final CounterItem counterItem;
counterItem = data.get(position);
nameView.setText(counterItem.getName());
if(counterItem.getDesc().length() == 0){
descView.setVisibility(View.GONE);
Log.d(HomeActivity.DEBUG_TAG, "GONE " + counterItem.getName() + ", LENGTH " + counterItem.getDesc().length());
}else
descView.setText(counterItem.getDesc());
countView.setText(counterItem.getCount() + "");
plusButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
counterItem.increment(helper.getWritableDatabase());
countView.setText(counterItem.getCount() + "");
}
});
View categoryView = view.findViewById(R.id.category);
String colors[] = {"#ff99cc00",
"#ff00ddff",
"#ffffbb33",
"#ffaa66cc",
"#ffcc0000"};
Random rand = new Random();
String color = colors[rand.nextInt(colors.length)];
categoryView.setBackgroundColor(Color.parseColor(color));
return view;
}
}
Row layout:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:baselineAligned="false"
android:descendantFocusability="blocksDescendants"
>
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_toLeftOf="#+id/linearLayout" android:layout_centerVertical="true"
android:gravity="center_vertical" android:paddingLeft="12dp" android:paddingRight="12dp"
android:paddingBottom="8dp" android:paddingTop="8dp" android:id="#+id/linearLayout1">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Counter name"
android:id="#+id/nameView"
android:textSize="16dp"/>
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
android:id="#+id/descView"
android:textSize="16dp"
android:textColor="#color/dividerGrey"
android:text="wtf"/>
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:id="#+id/linearLayout" android:gravity="center_vertical" android:layout_centerVertical="true"
android:paddingTop="8dp" android:paddingBottom="8dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="13"
android:id="#+id/countView"
android:textSize="30dp"
android:layout_marginRight="13dp" android:textColor="#color/dividerGrey"/>
<View android:layout_width="0.5dp" android:layout_height="48dp"
android:background="#color/dividerGrey" android:id="#+id/plusDivider"/>
<ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/plusButton"
android:src="#drawable/ic_button_increment"
style="#android:style/Widget.Holo.Light.ActionButton"
android:contentDescription="#string/plus_button"/>
</LinearLayout>
</RelativeLayout>
Well i suppose you use the ViewHolder pattern in a ListView right?
I don't want to try and explain the whole usage of this pattern as there are many other good tutorials.
So the case you describe happens, because the listAdapter reuses the convertView that was inflated for every object so if the last object for your listview has setVisibility(View.Gone) for your second line then when you scroll up all the other childs that become visible will also have visibility(View.Gone).
A simple workaround for this is to setVisibility for each row
like this:
if (convertView == null) {
convertView = (View) inflater.inflate(R.layout.view_item, null);
viewHolder = new ViewHolder();
viewHolder.itemName = (TextView) convertView.findViewById(R.id.item_name);
viewHolder.secondLine = (TextView) convertView.findViewById(R.id.second_line)
convertView.setTag(viewHolder);
}
else {
viewHolder = (ViewHolder) convertView.getTag();
}
if(<-- your condition here-->){
secondLine.setVisibility(View.VISIBLE);
}
else{
secondLine.setVisibility(View.GONE);
}
And now that you have added the code for your adapter i believe that your mistake is here:
if(counterItem.getDesc().length() == 0){
descView.setVisibility(View.GONE);
Log.d(HomeActivity.DEBUG_TAG, "GONE " + counterItem.getName() + ", LENGTH " + counterItem.getDesc().length());
}else {
**descView.setVisibility(View.VISIBLE);**
descView.setText(counterItem.getDesc());
}
You should add code to set it visible again if needed bacause with your code when it gets gone for one of the rows it stays gone forever.
Update
Also for your second problem, whenever you delete an item from your listview you should remove the item from the adapter and call notifyDataSetChanged(); in order for the adapter to recreate the Views.

Can't select ListView items

I have a ListView that uses a custom adapter. Each element in the ListView contains a RadioButton and a TextView.
Here is my adapter, it takes an ArrayList of Employees (An object that currently only contains a name):
public class EmployeeAdapter extends ArrayAdapter<Employee> {
private ArrayList<Employee> listEmployees;
// Give the adapter the context and layout we are operating it, as well as a list of employees to put in the list.
public EmployeeAdapter(Context context, int layout, ArrayList<Employee> listEmployees) {
super(context, layout, listEmployees);
this.listEmployees = listEmployees;
}
// We override the basic getView function since our list is custom.
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
// If there is nothing left to put in the view, inflate the view in the rowemployee layout.
if (v == null){
LayoutInflater vi;
vi = LayoutInflater.from(getContext());
v = vi.inflate(R.layout.rowemployees, null);
}
Employee i = listEmployees.get(position);
// Check if there's still an employee in the list.
if (i != null){
TextView name = (TextView) v.findViewById(R.id.text_employeename);
name.setText(i.getName());
}
// Alternate row colors.
if (position % 2 == 0) {
v.setBackgroundColor(Color.parseColor("#FFFFFF"));
} else {
v.setBackgroundColor(Color.parseColor("#e5fff4"));
}
return v;
}
}
Here is the listview declaration in my XML layout:
<ListView android:id="#+id/employees_list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:paddingLeft="2dp"
android:paddingRight="1dp"
android:background="#drawable/borderlist"
android:choiceMode="singleChoice"
android:listSelector="#48ad82"
android:layout_below="#id/employees_header">
</ListView>
And here is the layout of every item of the ListView:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/row_employee"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingLeft="10dp"
android:paddingTop="13dp"
android:paddingBottom="13dp"
android:descendantFocusability="blocksDescendants">
<RadioButton android:id="#+id/radio_employee"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:focusable="false"/>
<TextView
android:id="#+id/text_employeename"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="18sp"
android:layout_toRightOf="#id/radio_employee"
android:layout_marginTop="3dp"
android:layout_marginLeft="5dp"
android:focusable="false" />
</RelativeLayout>
I input a bunch of Employee objects into an ArrayList, which I push to the adapter, and then I set a setOnItemClickListener on the list. The listener contains this code:
OnItemClickListener onItemClickListener_employee
= new OnItemClickListener(){
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id){
Toast.makeText(getApplicationContext(), String.valueOf(view.isSelected()) , Toast.LENGTH_SHORT).show();
}
};
view.isSelected() always returns false. Why? I've been trying to figure out how to select an element on a list containing something else than just a TextView for a couple of hours, and the SDK documentation isn't very helpful, this is getting old.
When I press on the list's items, it seems like the TextView or the RadioButton get pressed instead. Shouldn't focusable="false" prevent this ( Android custom ListView unable to click on items )?
To get the item chosen, add the following method to your adapter (untested code):
public Employee getItemAt(int position){
return listEmployees.get(position);
}
Then in your handler, pass the position to the new adapter method above
public void onItemClick(AdapterView<?> parent, View view, int position, long id){
Employee e = adapter.getItemAt(position); //or whatever your adapter instance is named
Toast.makeText(getApplicationContext(), e.getName(), Toast.LENGTH_SHORT).show();
}
Since the view is just for displaying data, you really don't care about the view itself (unless you want to remove it, hilight it, etc).

Categories

Resources