I'm a bit new in Android, but I know the very basics from it, at least for the custom listview.
I was wondering, searching without much success, if there's a chance to make that items from the sides could have other styles. I'll explain me.
I've got an Horizontal listview. It shows 3 items (one in the middle and one half-cutted on each of the sides). Every item has it's own image with text below. I would like to make those items from the side have different stylings, like image with an opacity and text visibility gone.
May there's a way to know which item is in front and make it the reverse way, the layout with all text hidden and images with opacity, and the current item displayed (the middle one) with text visible and without opacity.
Edit: an schema of what I would like to reach (if possible of course)
You will have to create one Separate child.xml file to design row Element and then by the Help of Adapter you will have to pass every view to Adapter class.
this one is sample code for given to get your view in adapter class.
public View getView(int position, View convertView, ViewGroup parent) {
View rowView = convertView;
// reuse views
if (rowView == null) {
LayoutInflater inflater = context.getLayoutInflater();
rowView = inflater.inflate(R.layout.rowlayout, null);
// configure view holder
ViewHolder viewHolder = new ViewHolder();
viewHolder.text = (TextView) rowView.findViewById(R.id.TextView01);
viewHolder.image = (ImageView) rowView
.findViewById(R.id.ImageView01);
rowView.setTag(viewHolder);
}
Please check this website for more detail: http://www.vogella.com/tutorials/AndroidListView/article.html
In res/values/ folder style.xml file
create
<style name="CustomFontStyle">
<item name="android:layout_width">fill_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:capitalize">characters</item>
<item name="android:typeface">monospace</item>
<item name="android:textSize">12pt</item>
<item name="android:textColor">#00FF00</item>/>
</style>
then use in your view
<TextView
android:id="#+id/text_id"
style="#style/CustomFontStyle"
android:text="#string/hello_world" />
Related
I have a ListFragment that produces a list of 'cards' onscreen that look like this:
app screen mockup
The ListFragment uses a RelativeLayout to render each card:
<RelativeLayout
style="#style/CardDefault">
... many other elements here
</RelativeLayout>
The full XML for the card (above) is actually very verbose, as there are many more items in the card that are not in the screenshot. I omitted the extra stuff, because it's lengthy.
The style for card is as follows:
<style name="Card">
<item name="android:background">#drawable/card</item>
<item name="android:textColor">#color/card_text_default</item>
<item name="android:layout_height">match_parent</item>
<item name="android:layout_width">match_parent</item>
<item name="android:padding">16dp</item>
</style>
The default color of a card is the blue color, shown on top in the screenshot I linked to above. Once a card is completed, it gets the green style - the bottom card in the above screenshot.
I'd like to simply replace the blue style (shown above) with a green one. The style switch would happen when the view first loads - it's not something that would happen while the user is viewing this screen.
I've been playing around with different ways to do this, but can't seem to figure out what the best practice is.
It seems wasteful to have a completely different layout xml file merely to reference a different style attribute. Especially, when my layout xml file is very verbose, as I mentioned.
What's the best way for me to change the style on this Relativelayout I have?
Edit - 01/27
I've learned some more about Android, and have some more detail. I'd like to do something like the following code shows - the comments within the if blocks are pseudocode:
private class PrescriptionCardAdapter extends ArrayAdapter<Prescription> {
public PrescriptionCardAdapter(List<Prescription> prescriptions) {
super(getActivity(), R.layout.activity_fragment, prescriptions);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (null == convertView) {
if (cardState == "complete") {
// apply the COMPLETE theme or style to this specific view
convertView = getActivity().getLayoutInflater().inflate(R.layout.prescription_card, null);
}
else if (cardState == "overdue") {
// apply the OVERDUE theme or style to this specific view
convertView = getActivity().getLayoutInflater().inflate(R.layout.prescription_card, null);
}
else {
// apply the DEFAULT theme or style to this specific view
convertView = getActivity().getLayoutInflater().inflate(R.layout.prescription_card, null);
}
}
return convertView;
}
}
Is there a way I can apply a theme or a style to my views as they inflate them? Greg, could I do something with AttributeSets in the above code?
Thanks!
in my Android App I use an AlertBox for selecting icons.
This is done with a custom Adapter. I have a class comming from ImageView which changes the backgrond color for the old selected icon.
All works fine expect that I nees to reset the background color for converted views in the adapter. getBackGroundDrawable always return null? Any idea ???
public View getView(int position, View convertView, ViewGroup parent)
{
JIconImageView imageView = ((convertView == null) ? new JIconImageView(m_context) : (JIconImageView)convertView);
imageView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
imageView.setPadding(2, 2, 2, 2);
imageView.setIsSelected(m_selected == position);
imageView.setImageResource(JEntryIconHelper.getIconFromIndex(position));
return imageView;
}
and from public final class JIconImageView extends ImageViewenter code here
public void setIsSelected(boolean bSelected)
{
if (m_bSelected = bSelected)
setBackgroundColor(SELECTED_BACKCOLOR);
else setBackgroundDrawable(m_background);
}
As far as I know, there's no easy way to get the current theme background color.
One reliable way to do what you want is to save the original background color in a member variable during getView (or you could do this once, earlier, by creating a throwaway JIconImageView). For example, at the point where you bind the adapter:
JIconImageView imageView = new JIconImageView (...);
Drawable origBackground = imageView.getBackground();
imageView = null;
Then, reference imageView.getBackground() in setIsSelected().
Another way would be to use an xml selector; this goes in your "drawables" folder:
<selector
xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:state_selected="true"
android:drawable="#drawable/your_selected_drawable" />
<item
android:drawable="#drawable/your_unselected_drawable" />
</selector>
As you can see, this solution uses drawables rather than colors but, if your icons are fixed size, that is a trivial difference (maybe something similar can be done with colors -- you'll have to research that). The drawback to this method is that you have now hard coded the background colors. At least the definitions are in your resources, though.
You could build on the above by referencing an android style in your icon definition, something like this:
<JIconImageView
android:id=...
android:background="#drawable/jicon_background_selector />
I'm working on an app that is basically done but I'm reviewing the code to optimize. I found a Guide to inflating which states that its well to use the "parent" part of the inflate so that you can keep the layoutparams - which I in my original version did not do - instead I set these programmatically.
Now onward to the problem. I've changed my code (look below) to incorporate the View but the layoutparameters are not added, and I still have to add them programmatically.
The original code, this works however I'm not happy with having to set the layoutparams
(observe that I've shorten the code a bit to make it easier to read, I have not removed anything of interest):
// this is the parent
LinearLayout llCategory = (LinearLayout) findViewById(R.id.llCategory);
categoryArrayList = db.getCategory(); // this gets the data for me.
// Add the Categories
for (int i = 0; i < categoryArrayList.size(); i++) {
LayoutInflater layoutInflater = (LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
// This is my original inflate
//View view = layoutInflater.inflate(R.layout.row_standard, null);
// this is the inflate I would like to use.
View view = layoutInflater.inflate(R.layout.row_standard, llCategory, false);
LinearLayout llCard = (LinearLayout) view.findViewById(R.id.llStandardCard);
// here is some code where I change the background of llCard - which is the base layout for the view I inflated above.
// this is where I have to set the paddings programmatically on the view (or rather the linear layout that the view contains)
// get the right paddings for the card and set them.
int standardPadding = (int)getResources().getDimension(R.dimen.standard_padding);
int bottomPadding = (int)getResources().getDimension(R.dimen.standard_card_padding_bottom);
llCard.setPadding(standardPadding, standardPadding,standardPadding,bottomPadding);
// Add the complete view to the layout.
llCategory.addView(view);
}
So to recap. Regardless whether I use this version of inflate:
View view = layoutInflater.inflate(R.layout.row_standard, null);
or if I use this version of inflate:
View view = layoutInflater.inflate(R.layout.row_standard, llCategory, false);
I have to set the padding (which is already set in the XML) programmatically - what am I doing wrong.
Edit, adding XML:
<?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="wrap_content">
<LinearLayout
android:id="#+id/llStandardCard"
style="#style/StandardCardStyle">
<TextView
android:id="#+id/tvStandardRowText"
style="#style/RowText"/>
</LinearLayout>
</LinearLayout>
Also the style:
<style name="StandardCardStyle" parent="#style/AbstractCard">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_marginTop">#dimen/standard_half_padding</item>
<!--Very custom paddings due to the background messing with the standard ones-->
<item name="android:paddingLeft">#dimen/standard_padding</item>
<item name="android:paddingRight">#dimen/standard_padding</item>
<item name="android:paddingTop">#dimen/standard_padding</item>
<item name="android:paddingBottom">#dimen/standard_card_padding_bottom</item>
<item name="android:layout_gravity">top</item>
<item name="android:clickable">true</item>
</style>
LayoutParams as you can see here are part of a groupview. They are used by views to tell their parents how they want to be laid out. They have nothing to do with paddings. Padding is part of the view itself. Your problem is that you cannot preserve the paddings of your llCard which are defined in the xml files.
My best guess based on the info of your question (and comments) is that you are using paddings both in the xml layout file and in the selectors and or in the 9 patches. I think that padding defined in the 9 patches takes higher priority because they are applied during the drawing of the view and thus the paddings from xml layout are ignored.
So my suggestion is to either use your paddings ONLY in the 9 patches or ONLY in the xml layout NOT in both.
Take a look here about the 9 patches padding area.
Hope this helps...
I am using multiple choice ListView items. The user can select multiple items. So I wanted to highlight the items selected by the user by changing either the text color or background color of the list row. I have gone through stack overflows links but didn't get the proper solution. When I am trying to do it, it is randomly changing any unselected item background color. Help!!!
public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
videocursor.moveToPosition(position);
v.setBackgroundColor(Color.parseColor("#80B7DBE8"));
SaveSelections();
}
That randomly changing background color is due to the reason that ListView recycles views in its list to avoid unnecessary memory consumptions. You need to provide your own custom adapter in which you need to override getView method and perform some checks to highlight only those list items who have some kind of flag set to true for background color
Far better than the above suggestions is to use a selector, also known as a state-list drawable. That way, the OS takes care of all of the business of color highlighting, etc.
more explicitly, take the following xml and save it under res/drawable as something like li_background.xml (I'm using images, but feel free to swap out colors as is appropriate to your situation)
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:state_focused="true"
android:drawable="#drawable/list_item_pressed" />
<item android:state_pressed="true"
android:drawable="#drawable/list_item_pressed" />
<item android:state_selected="true"
android:state_activated="true"
android:drawable="#drawable/list_item_selected" />
<item android:state_activated="true"
android:drawable="#drawable/list_item_selected" />
<item android:state_selected="true"
android:drawable="#android:color/black" />
<item android:drawable="#android:color/transparent" />
</selector>
and set the background of All ListItems in the ListView to R.drawable.li_background. if your listView is properly configured for multiple selections (android:choiceMode="multipleChoice" or listView.setChoiceMode(AbsListView.CHOICE_MODE_MULTIPLE); if you prefer) then android will take care of the rest. This stuff isn't well documented, I had a hard time finding the solution and I see similar questions all the time, but the relevant dos are here and here
Wagas is correct. In your adapter's getView, you are passed a View (called convertView by Eclipse's autocomplete). This is because ListViews recycle the views for each row. If you set a property for a given View, it will retain that property when it is recycled.
For this reason, you should never set the properties of anything in a given row's View outside the getView method of the Adapter backing the ListView.
There are a number of ways you could handle this, but the basic idea is that you want to set some piece of data that uses the position passed in to onItemClick to set a flag. Then check the flag in the Adapter's getView to decide how to set the background for the row's View.
For example, if only one item can be selected, you might just set a member variable, say mPosition on the Adapter itself to the position passed in to onItemClick, and then check in getView if position == mSelectedPosition to decide how to set the View. If multiple items can be selected, perhaps you set a member variable on each object contained in the Adapter.
You probably should override getView() in the adapter, and change the row background color in there.
An example:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView != null) {
if (mSelectedPositions.contains(position)) {
convertView.setBackgroundColor(Color.parseColor("#3fa9f5"));
} else {
convertView.setBackgroundColor(Color.parseColor("#ffffff"));
}
}
return super.getView(position, convertView, parent);
}
in onItemClick() just use adapter.notifyDataChange(); also set a flag to true;
in the getView() of your CustomAdapter use boolean flag to know whether the row was selected or not.
Then just check that flag and proceed as you want
i.e.,
if(flag){
v.setBackgroundColor(Color.parseColor("#80B7DBE8"));
}else{
v.setBackgroundColor(Color.parseColor("#FF0000"));
}
I saw an app that had a nice menu structure which I want to replicate in my own app and wanted to know how you think it's done and how I should approach it. Here's a screenshot:
It's from the CRM mobile app (MECRM) and to me, it appears to be a ListView with headers and images. But I'm wondering are they images or buttons with images as a background because of 2 things;
1.) the first image "Announcements" is cut off so if that was an ImageView, I'm not too sure if it would do the same.
2.) The Opportunity image has a different image when pressed (as do all the other images).
I guess my question is what controls would I need use to replicate this?
This sort of view is absolutely possible using ListView
You're going to need to implement your own ListAdapter with custom getView behavior.
Based on the position of the view, you can either render an inactive divider view (that won't be clickable), or you can then render a gridview for the appropriate category. This tutorial can get you started on implementing custom adapters with getView.
Here's some sample code on what getView might look like
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
boolean isDivider = false //TODO logic here
if (isDivider){
if (v == null) {
LayoutInflater li = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = li.inflate(R.layout.custom_adapter_item, null);
}
Map<String, String> item = items.get(position);
initView(v, item);
return v;
} else{
View v = null //TODO init divider view here
return v;
}
}
private void initView(View v, Map<String, String> item) {
String[] keys = DummyData.columns;
((TextView) v.findViewById(R.id.value_left)).setText(item.get(keys[0]));
((TextView) v.findViewById(R.id.value_right)).setText(item.get(keys[1]));
}
You're going to have to inflate your gridview layout where I inflate my custom_adapter_item, but this is the framework for a custom listview with complex list items
Your view hierarchy will end up looking something like this
ListView
Category1Header (LinearLayout))
Title (textbox)
Category1Contents (Gridview)
Cat1Cont1 (LinearLayout)
icon (image)
description (textbox)
Category2Header
You get the idea
It seems a Collection of GridViews with 5 columns. ELement of columns are TextView, and ImageView.
I think to get this type of layout list view is not sufficient.
You have to use ScrollView as parent, TextView and GridView as one layout and each this type of layout as children in ScrollView as below.
child_view
<LinearLayout vertical >
<TextView />
<GridView />
</LinearLayout>
main_view
<ScrollView>
<child_view />
<child_view />
<child_view />
.......
</ScrollView>
I hope it may help you.
For something like this I wouldn't recommend Listview as a base. Listview is usefull if you have a lot of similar items that should react in a similar way. For small qty. Of items with a lot of variation it is not your best choice.
As basis I would use linearlayout or relative layout (depending on how you want to react on different screen sizes).
I would style TextViews with an according 9-patch background to look like the headers.
For the buttons I would use the Button widget with a selector as android:background.
Therefore create a XML file with below code in your drawable folder and exchange the drawable with the names of your drawables.
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_focused="true" android:state_pressed="false" android:drawable="#drawable/btn_add_sel0" />
<item android:state_focused="true" android:state_pressed="true" android:drawable="#drawable/btn_add_presssel0" />
<item android:state_focused="false" android:state_pressed="true" android:drawable="#drawable/btn_add_press0" />
<item android:drawable="#drawable/btn_add_norm0" />
</selector>