Custom menu item in ActionBarSherlock - android

I need to have a custom menu item in the ActionBar that just displays some custom formatted text. So I thought I would create an image on the fly and attach that to an menu icon. So in my code I thought I could use Layout xml to compose my text:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView android:textColor="#bcbcbb"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="Some Text"/>
<TextView android:textColor="#ffffff"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:id="#+id/replace_text" android:text="XXXX"/>
</LinearLayout>
Then create a temp layout drawing that to a DrawableBitmap:
LinearLayout layout = (LinearLayout)View.inflate(getApplicationContext(), R.layout.refund_text, null );
layout.setDrawingCacheEnabled(true);
layout.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
layout.layout(0, 0, mRefundLayout.getWidth(), layout.getHeight());
layout.buildDrawingCache(true);
Bitmap bitmap = Bitmap.createBitmap(layout.getDrawingCache());
BitmapDrawable bm = new BitmapDrawable( getBaseContext().getResources(), bitmap);
layout.setDrawingCacheEnabled(false);
....do something with the bitmap
However after the measure call width and height are still zero. Can anyone tell me what I'm doing wrong?
Regards
Lee

If you only want to control the colours of the text in the MenuItem, you might be able to simply get away with formatting (using SpannableStringBuilder) the CharSequence you pass to MenuItem.add(int groupId, int itemId, int order, CharSequence title). I haven't tried that, let us know if it works!
If you ultimatately want to do more than that then create your own custom ActionProvider, inflating your layout in onCreateActionView() and "doing stuff" in onPerformDefaultAction().

Related

Android spinner popup dropdown position and size

I managed to change the Spinner background and it's popup dropdown background. I can adjust the popup android:dropDownHorizontalOffset and android:dropDownVerticalOffset.
I also have a custom layout for the spinner items.
But, i am stuck with this look:
Notice how the items are outside the boundries of the popup dropdown. How can I fix that? Is there a way to insert padding for the top and bottom of the items somehow?
<Spinner
android:id="#+id/branchesSpinner"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_marginStart="8dp"
android:background="#drawable/dropdown_base"
android:dropDownHorizontalOffset="-5dp"
android:dropDownVerticalOffset="50dp"
android:paddingBottom="10dp"
android:paddingLeft="20dp"
android:popupBackground="#drawable/rounded_rectangle_4"
/>
spinner_item_custom_layout:
<?xml version="1.0" encoding="utf-8"?>
<TextView 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:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="10dp"
android:textColor="#color/charcoal"
android:textStyle="bold"
tools:text="Select Branch"></TextView>
N.B: The backgrounds I added are .PNG images and not XML
Because you are using a png file as popup background for the spinner so there are 2 limitations
If you run the app on devices which have high screen density, your spinner background might be stretch and look so ugly.
You cannot set padding for you popup background, that why sometimes your content is not looking good as you expected.
Solution: Using 9-patch images. You can take a look a guide from Android official site about how to use draw9patch
I've just used draw9patch tool to edit your rounded_rectangle_4.png.
You can replace with your current background then give it a try.
You need to create custom adapter for your spinner.
Then, in getDropDownView method of the adapter class you need to set top margin of the dropdown item when the position is 0 using below code
public static void setMargins (View v, int l, int t, int r, int b) {
if (v.getLayoutParams() instanceof ViewGroup.MarginLayoutParams) {
ViewGroup.MarginLayoutParams p = (ViewGroup.MarginLayoutParams) v.getLayoutParams();
p.setMargins(l, t, r, b);
v.requestLayout();
}
}
Just make your logic to compare the position of dropdown child.
Note that you need to set only top margin.

TabLayout : Set custom color for each tab

I saw a lot of questions that say how to set the color differently for selected(active) and unselected(inactive) tabs. I also know that google provides void setTabTextColors (int normalColor, int selectedColor) to achieve this.
My requirement is a little different, I am working on a quiz app with a TabLayout and CardView. TabLayout allows the user to navigate between questions and CardView is used to display the questions.
I need to set the color of the tabs for which the user has already selected an answer differently than that for which the user has not answered yet. By default the TextColor is black but if the user selects an answer then the tabcolor should change to blue (just for eg.) and it should remain that way till the user exits. I have a int array called Select that will hold the value of the option that the user has selected (The values range between 1 - 4). While allocating the Select array I also initialize it with -1. I thought of setting up a loop and then if the array is -1 leave the tab as it is or set the tabcolor to blue.
How can I achieve this functionality?
You can work with TabLayout internals by querying for this children and changing TextViews manually. This can break your code when you upgrade to another support library version, but as long as you keep track and test when updating, it should work:
private void updateTabTextColors() {
LinearLayout tabsContainer = (LinearLayout) mTabLayout.getChildAt(0);
for (int i = 0; i < mTabLayout.getTabCount(); i++) {
LinearLayout item = (LinearLayout) tabsContainer.getChildAt(i);
TextView tv = (TextView) item.getChildAt(1);
tv.setTextColor(Select[i] == -1 ? Color.BLACK : Color.BLUE);
}
}
Just enhancing Marcelo Liberato's answer to support custom background for each tab item.
LinearLayout tabsContainer = (LinearLayout) mTabLayout.getChildAt(0);
LinearLayout childLayout1 = (LinearLayout)tabsContainer.getChildAt(2);
LinearLayout childLayout2 = (LinearLayout)tabsContainer.getChildAt(3);
LinearLayout tabView = (LinearLayout) childLayout1.getChildAt(0).getParent();
tabView.setBackgroundResource(R.drawable.ic_blue_selector);
tabView = (LinearLayout) childLayout2.getChildAt(0).getParent();
tabView.setBackgroundResource(R.drawable.ic_red_selector);
Custom xml file:
<?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:id="#+id/ll_tab_holder"
android:orientation="vertical">
<LinearLayout
android:id="#+id/ll_tab_icon_title_holder"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ImageView
android:id="#+id/tab_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:scaleType="fitCenter" />
<TextView
android:id="#+id/tab_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:textAppearance="#style/lasuCustomTabText" />
</LinearLayout>
<TextView
android:id="#+id/tab_only_title"
android:layout_width="match_parent"
android:layout_height="56dp"
android:textAllCaps="true"
android:textSize="12sp"
android:layout_gravity="center"
android:gravity="center"
android:textColor="#drawable/ic_tab_text_color_selector" />
</LinearLayout>
Output:
If you are interested in using a library for this functionality, this library works well.
https://github.com/astuetz/PagerSlidingTabStrip
As in the doc getTabTextColors() -> Gets the text colors for the different states (normal, selected) used for the tabs. the tabs can only have 2 states. The only way to achieve what you want if to inherit Tab class and add a new state, something like: tabAlreadyVisited. Then #Override the draw method to change background color based on the tabAlreadyVisited attribute value. Or change the text color with setTabTextColors
It's possible to set custom view for your tab
TabLayout.Tab yourTab = tabLayout.newTab();
yourTab.setCustomView(R.layout.red_text_view);
And red_text_view.xml is
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#android:id/text1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fontFamily="sans-serif-medium"
android:gravity="center"
android:textColor="#f44336"/>
If you use the #android:id/text1 default Tab's settext should work. You could do whatever you want with your custom view.

How can I change the color of my text based on the color of the ImageView it overlays?

So I've got transparant buttons with white text labels set up over a user uploaded ImageView. If the user uploads an image that is mostly white, then the buttons are hard to see if not completely invisible.
Does anyone know of a way to get the average color of a ImageView's source picture/drawable? If I can do this, I can compare it to a certain threshold I can trial and error for... If I can get this, then I can change the color of the text on my buttons to the inverted version of this color...or something??
Just idea spitting here..
And of course, if someone knows a better way, more info would be much appreciated, thanks!!
You could use the Palette class.
From the developers guide:
You can retrieve the prominent colors from the image using the getter
methods in the Palette class, such as Palette.getVibrantColor().
Palette.from() expects a Bitmap param, so you'll have to get it from your ImageView.
Something like this should work:
Bitmap bitmap = ((BitmapDrawable) imageView.getDrawable()).getBitmap();
Palette colorPalette = Palette.from(bitmap).generate();
And then you can call the appropriate methods on this Palette instance to get the prominent colors, for example:
int darkVibrantColor = colorPalette.getDarkVibrantColor(someDefaultColor);
Check out this example screenshot on how the Palette class recognizes colors:
You can use Palette to get color of bitmap in an imageview
bitmap = BitmapFactory
.decodeResource(getResources(), R.drawable.header);
Palette.from(bitmap).generate(new Palette.PaletteAsyncListener() {
#Override
public void onGenerated(Palette palette) {
//Set normal shade to textview
int vibrantColor = palette.getVibrantColor(R.color.primary_500);
//Set darkershade to textview
int vibrantDarkColor = palette
.getDarkVibrantColor(R.color.primary_700);
}
});
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:gravity="center"
android:layout_height="match_parent">
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:layout_width="110dp"
android:layout_height="110dp"
android:layout_gravity="top|center"
android:background="#drawable/noimage"
android:scaleType="fitXY" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center"
android:text="Upload image"
android:textColor="#fff"
android:background="#34000000" />
</FrameLayout>
</LinearLayout>
You can set transparent color to button view . So button text is visible even if image is in white color. If its okay dont forget to thumb up answer!!

Adding ImageView to LinnearLayout dynamically goes wrong

I wrote a small function
private void addTabIndicators(int tabCount){
LinearLayout indicatorsContainer = (LinearLayout)findViewById(R.id.indicators_container);
for(int i = 0; i<tabCount; i++){
ImageView indicator = (ImageView)this.getLayoutInflater().inflate(R.layout.tab_indicator, null);
indicatorsContainer.addView(indicator);
}
}
that is supposed to add circles to the linearlayout in my activity based on how many tabs are in the pager adapter. Everything would be cool BUT, the imageviews i add instead of beeing the size declared in the xml layout, are being resized to 1x1px... Any ideas where i could go wrong? Here are the layouts for the indicator and linear layout
tab_indicator.xml:
<?xml version="1.0" encoding="utf-8"?>
<ImageView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="64dp"
android:layout_height="64dp"
android:layout_margin="8dp"
android:src="#drawable/floating_button_background"/>
The indicators container:
<LinearLayout
android:layout_marginBottom="16dp"
android:orientation="horizontal"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:id="#+id/indicators_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</LinearLayout>
The fault might be here
ImageView indicator = (ImageView)this.getLayoutInflater().inflate(R.layout.tab_indicator, null);
You need to pass the root view of your image view to provide the layouts defined in your XML. If you pass null instead, default layoutparams are set.
Place
ImageView indicator = (ImageView)this.getLayoutInflater().inflate(R.layout.tab_indicator, your root view of image view,false);
This is a very common mistake. Never pass null except you really know what you are doing.
Read more here:
http://developer.android.com/reference/android/view/LayoutInflater.html
Hope it helps

Listview changing size of (reused) views

I am all for reusing views in listview. I always set visibility, contents, witdth etc. of all controls again in getView Unfortunately it seems ListView fails to recalculate height.
Picture one shows the initial item showed:
Picture two shows how item one is rendered after we scrolled away and back into it
The background linearlayout height (the black area) made me think that in picture two, Android is reusing a view that just showed a much heigher item (e.g. the second item). But why does it not recalibrate/reset/recalclulate itself (it is in "wrap_content" mode in its XML) when reused as view for the first item which content (text + image) is not as heigh?
In truth I am not sure what is happening. The problem only manifests itself if I have image in the view. I have tried organize the bitmap/image loading in different ways (sample code underneath) with different things commented out, but that does not seem to make much difference. I am really at a loss here as to the reason.
override_listitem_news.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="10dip"
android:background="#android:color/black"
>
<TextView
android:id="#+id/listitem_news_label"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textStyle="bold"
android:textSize="22sp"
android:padding="5dip"
android:text="#string/newsItemTitle"/>
<TextView
android:id="#+id/listitem_news_date"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textStyle="italic"
android:textSize="15sp"
android:padding="5dip"
android:text="#string/newsItemDate"/>
<TextView
android:id="#+id/listitem_news_content"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textStyle="normal"
android:textSize="15sp"
android:padding="5dip"
android:autoLink="web"
android:text="#string/newsItemDesc"
android:background="#android:color/darker_gray"
/>
<ImageView
android:id="#+id/listitem_news_icon"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
</LinearLayout>
Here is code where I load image in getView
ViewTreeObserver vto = image.getViewTreeObserver();
vto.addOnGlobalLayoutListener(
new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
image.getViewTreeObserver().removeGlobalOnLayoutListener(this);
image.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
SharedCode.sharedUtilScaleImage_Width(image);
}
}
);
image.setTag(data.image_file_name + data.image_file_url);
Bitmap bit = null;
bit = SharedCode.sharedGetFileFromOffline(thisActivityContext, "news", data.image_file_name, MyGetKindOfFile.ImageAsBitmap).bitmap;
if (bit != null) {
image.setImageBitmap(bit);
image.setVisibility(View.VISIBLE);
}
else {
image.setImageBitmap(null);
image.setVisibility(View.GONE);
}
image.setPadding(0, 0, 0, 0);
image.setBackgroundColor(data.backgroundColorInt);
For what it is worth, problem appeared to be related to the imageview. Just for reference, I will write here how I solved it.
In getView I fixed the imageview width to screen width (instead of "wrap-content" and/or parent view width - earlier code used OnGlobalLayoutListener for parent width)
I switched over to using SetDrawable instead of SetImageBitmap. It is odd, but this difference was actual very important in solving the odd space around the imageview after scrolling an item/row in/out of view.
My research did also indicate that others had problems using wrap_content in listview for cases similar to mine, but I was not able to find anyone who had experienced exact same problems as me.

Categories

Resources