Android setting LinearLayout background programmatically - android

I have a situation where I need to set a background on a LinearLayout programatically.
In my layout, I am setting my background using `android:background="?android:attr/activatedBackgroundIndicator", but I want to set this programatically:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/myLayoutId"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:gravity="left|center"
android:paddingBottom="5dip"
android:paddingLeft="5dip"
android:background="?android:attr/activatedBackgroundIndicator"
android:paddingTop="5dip" >
I've tried using:
Drawable d = getActivity().getResources().getDrawable(android.R.attr.activatedBackgroundIndicator);
rootLayout.setBackgroundDrawable(d);
But it crashes. Any ideas?
Edit: I had also tried using:
rootLayout.setBackgroundResource(android.R.attr.activatedBackgroundIndicator);
10-08 15:23:19.018: E/AndroidRuntime(11133): android.content.res.Resources$NotFoundException: Resource ID #0x10102fd

I had the same problem and I fixed it using this piece of code.
The android.R.attr.* are pointers to the in a theme and not to the actual drawable resource defined. You have to use the TypedArray to access the id.
theView = this.inflater.inflate(R.layout.list_row_job_favorited, null);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) {
TypedArray a = mContext.obtainStyledAttributes(new int[] { android.R.attr.activatedBackgroundIndicator });
int resource = a.getResourceId(0, 0);
//first 0 is the index in the array, second is the default value
a.recycle();
theView.setBackground(mContext.getResources().getDrawable(resource));
}
I used this in my custom list adapter when detects SDK upper and worked fine.

try this line
rootLayout.setBackgroundResource(d);
instead of
rootLayout.setBackgroundDrawable(d);

try this
rootLayout.setBackgroundResource(R.drawable.image);

It's a bad idea doing it the way the accepted answer tells you to. The problem is that you also need to call the list's onItemCheckedStateChanged to update what's needed (the action bar title for example).
In that case all you need to do is simply call getListView().setItemChecked(position, true); when the item is checked and getListView().setItemChecked(position, false); when it's not checked.

Please try the following code.
LinearLayout layout=(LinearLayout) findViewById(R.id.layoutImage);
layout.setBackgroundResource(R.drawable.bg);

You can use something like this
TypedValue outValue = new TypedValue();
context.getTheme().resolveAttribute(android.R.attr.selectableItemBackgroun d, outValue, true);
view.setBackgroundResource(outValue.resourceId);

Related

getCompoundDrawables returns null inside of onCreateView, but not later

I want to run the code below in order to tint a button's drawable on pre-lollipop devices, however button.getCompoundDrawables() is returning null for all 4 elements of the array when called inside of the Fragment's onCreateView method.
If I inspect the same Drawable[] array at a later point in time - say upon a button click event - I can see the drawable value has been correctly assigned (3 are null, 1 is valid).
Is there some button life cycle or fragment life cycle that I can rely on the compound drawables array to have been already properly initialized?
Drawable[] drawables = button.getCompoundDrawables();
if( drawables[2] != null){
Drawable wrapDrawable = DrawableCompat.wrap(drawables[2]);
DrawableCompat.setTint(wrapDrawable, color);
button.invalidate();
}
Here's the lib versions I'm using:
compile 'com.android.support:appcompat-v7:24.1.1'
compile 'com.android.support:support-v4:24.1.1'
compile 'com.android.support:design:24.2.0'
At request, I'm including also some xml code:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
[...] >
<Button
android:id="#+id/bt1"
android:background="#android:color/transparent"
android:textAppearance="#style/ConfigButtonTheme"
android:text="Sincronizar Música"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:drawableEnd="#drawable/ic_chevron_right_white_24dp"
android:textAlignment="textStart"
android:layout_width="match_parent"
android:layout_height="60dp" />
</LinearLayout>
for android:drawableRight, you should use getCompoundDrawables(), where as for android:drawableEnd, you should use getCompoundDrawablesRelative().
getCompoundDrawablesRelative()
Change android:drawableEnd to android:drawableRight. Not sure why but drawableEnd returns null in onCreate() method and drawableRight works fine.
You could configure the drawable programmatically and then set it into the text view like so.
val textDrawable = resources.getDrawable(R.drawable.ic_arrow_upward_24dp, null)
val color = ResourcesCompat.getColor(resources, R.color.colorAccent, null)
textDrawable.setTint(color)
//setCompoundDrawablesRelativeWithIntrinsicBounds(left, top, right, bottom)
textView.setCompoundDrawablesRelativeWithIntrinsicBounds(null, textDrawable, null, null)
Change android:drawableEnd to android:drawableRight. Not sure why but drawableEnd returns null in onCreate() method and drawableRight works fine.
OR
Another way to do without changing android:drawableEnd to android:drawableRight.
It will work 100%
just write your code as follow:
onCreate(){
//your all statement
//at the end
findViewById(android.R.id.content).post(new Runnable() {
#Override
public void run() {
//write your code here you will get all the drawables
}
});
}
In Kotlin returns a list of drawables:
val drawables = (compoundDrawables zip compoundDrawablesRelative).map {
it.first ?: it.second
}
My guess is that the drawable hasn't been created/inflated yet. Try putting that code in either onActivityCreated, onStart or onResume within the Fragment. These are in order of when they will be called within the lifecycle, ideally you want to do this as soon as possible.
It doesn't load your drawables within TextView at the beginning. You should use
TextView.post({
// get your drawables here.
})
this function to get your drawables when it's loaded.

Android dataBinding - How to get resource id of a View in xml

In Android Studio my data binding itself works and is set up fine. I have a boolean defined like this:
<resources>
<bool name="showAds">false</bool>
</resources>
and in a layout.xml file i would like to referenced this boolean (which works fine) but i want to assign a id based on this boolean. Let me show you what i am trying to accomplish:
I have a button that is in a relativeLayout tag and depending on this boolean i would like to reposition the button. So I have this:
<Button
android:id="#+id/startButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="64dip"
****************
android:layout_below="#{#bool/showAds ? #+id/adone : #+id/title_main}"
****************
android:layout_centerHorizontal="true"
android:textColor="#0080FF"
android:text="#string/start_btn_title" />
See what i want to to do? I want to layout the button below a layout called adone if the showAds boolean is true, otherwise place it below a layout called title_main. Whats the syntax for this as what I have here is not compiling. I get a compile error:
expression expected after the second # sign
The above is the same problem as in How to get dimensions from dimens.xml
None of the LayoutParams attributes have built-in support. As answered in the linked article, data binding of LayoutParams was thought to be too easy to abuse so it was left out of the built-in BindingAdapters. You are not abusing it, so you should add your own.
#BindingAdapter("android:layout_below")
public static void setLayoutBelow(View view, int oldTargetId, int newTargetId) {
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams)
view.getLayoutParams();
if (oldTargetId != 0) {
// remove the previous rule
layoutParams.removeRule(RelativeLayout.BELOW);
}
if (newTargetId != 0) {
// add new rule
layoutParams.addRule(RelativeLayout.BELOW, newTargetId);
}
view.setLayoutParams(layoutParams);
}
As an aside, the #+id/adone in the binding syntax will not create the id. You should create the id in the View you're binding to.

Change value in layout.xml conditionally in Android

I'm trying to get android:layout_marginEnd="-6dp" to change to 2dp conditionally in:
<FrameLayout
android:id="#+id/wifi_combo"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_marginEnd="-6dp"
>
My condition is:
if (mSignalClusterStyle == STYLE_ALWAYS) {
mMobileType.setVisibility(View.VISIBLE);
} else if (mWifiVisible) {
mMobileType.setVisibility(View.GONE);
}
I would like to add a line to the if statement that overrides the -6dp with 2dp in the xml file.
I have explored setMarginEnd(), but there are very few resources on this, seeing as it is only a year old, and I keep getting a compile error with it.
What is the best way to change android:layout_marginEnd on a condition programmatically?
FrameLayout layout = (FrameLayout) findViewById(R.id.wifi_combo);
FrameLayout.LayoutParams params = (LayoutParams) layout.getLayoutParams();
params.setMarginEnd(2);
The correct way to set the endMargin is using setMarginEnd() only, added in API 17.
http://developer.android.com/reference/android/view/ViewGroup.MarginLayoutParams.html#setMarginEnd(int)
BTW, what compile errors you are getting?

Change the Color of ScrollView Programmatically

What I'm currently doing
Currently, I have changed the scrollbar in my XML file using the android:scrollbarThumbVertical property like so:
<ScrollView
android:id="#+id/scrollView1"
android:scrollbarThumbVertical="#drawable/scrollbar_blue"
... >
And scrollbar_blue refers to my scrollbar_blue.xml file, which is this:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
<gradient
android:angle="45"
android:centerColor="#color/blue"
android:endColor="#color/blue"
android:startColor="#color/blue" />
<corners android:radius="8dp" />
</shape>
What I want to do
I have a colour option for my app - so when the colour is on, it should stay blue; otherwise, it should be grey.
How can I programmatically (in my activity class) change my ScrollView to use my scrollbar_grey.xml?
If you look at the Android documentation on ScrollView, there is no corresponding method to android:scrollbarThumbVertical
I'm fine with another way change the colour as well.
Here is how I create the reference to my ScrollView:
ScrollView scr = (ScrollView)findViewById(R.id.scrollView1);
There is a method to change it programmatically but that method is not exposed. There doesn't seem to be anything else to change it programmatically from what I have read.
However, I did come across this one stackoverflow answer that uses reflection to do it.
Please upvote the answer there if it works for you: https://stackoverflow.com/a/19819843/3286163
The answer was for a listview but is the same for the scrollview:
ScrollView scr = (ScrollView)findViewById(R.id.scrollView1);
try
{
Field mScrollCacheField = View.class.getDeclaredField("mScrollCache");
mScrollCacheField.setAccessible(true);
Object mScrollCache = mScrollCacheField.get(scr); // scr is your Scroll View
Field scrollBarField = mScrollCache.getClass().getDeclaredField("scrollBar");
scrollBarField.setAccessible(true);
Object scrollBar = scrollBarField.get(mScrollCache);
Method method = scrollBar.getClass().getDeclaredMethod("setVerticalThumbDrawable", Drawable.class);
method.setAccessible(true);
// Set your drawable here.
method.invoke(scrollBar, getResources().getDrawable(R.drawable.scrollbar_blue));
}
catch(Exception e)
{
e.printStackTrace();
}
Only thing I could find. I gave it a try myself and it worked.
In API 29+ use ScrollView.setVerticalScrollbarThumbDrawable() otherwise use the accepted answer.
It is easy nowadays :)
scrollView.verticalScrollbarThumbDrawable = ColorDrawable(Color.CYAN)
scrollView.horizontalScrollbarThumbDrawable = ColorDrawable(Color.WHITE)
This method requires API 29 and higher :
public static void changeBarColor(ScrollView sv, int thumbColor,int trackColor) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
sv.getVerticalScrollbarThumbDrawable().setTint(thumbColor);
sv.getVerticalScrollbarTrackDrawable().setTint(trackColor);
}
}

Facebook LoginButton for Android does not take login_text and logout_text values passed from XML

Facebook Sdk for Android does not take login_text and logout_text values passed from XML. It just ignores it. There is no documentation/example available on earth which uses this customization of the button.
<com.facebook.widget.LoginButton
xmlns:fb="http://schemas.android.com/apk/res-auto"
android:id="#+id/connectWithFbButton"
style="#style/com_facebook_loginview_default_style"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_gravity="center_horizontal"
android:text="#string/connect_with_facebook"
fb:login_text="#string/connect_with_facebook"
fb:logout_text="Connecting with facebook" />
It always says Login In or Log Out. How can I use this property? I tried debugging through the LoginButton code but in vain. It never goes through any of the constructors of LoginButton() and hence cannot parse my custom parameters.
Did someone face this issue?
Solved!!
Add string with name "com_facebook_loginview_log_in_button" to strings.xml located in res>values>strings.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="com_facebook_loginview_log_in_button">Connect</string>
<string name="com_facebook_loginview_log_out_button">Your Logout</string>
</resources>
Your first solution is correct.
It didn't worked because you've defined the style atrribute:
style="#style/com_facebook_loginview_default_style"
From the LoginButton source code:
public LoginButton(Context context, AttributeSet attrs) {
super(context, attrs);
if (attrs.getStyleAttribute() == 0) {
do stuff ...
}
}
So, it will only look at the defined attribute "login_text" if you leave "style" attribute undefined.
Gabriel is spot on. To fix this, go to LoginButton.java in Facebook SDK and move the parseAttributes call
parseAttributes(attrs)
to the bottom so that it always runs.
Whole method will look like this :
public LoginButton(Context context, AttributeSet attrs) {
super(context, attrs);
if (attrs.getStyleAttribute() == 0) {
// apparently there's no method of setting a default style in xml,
// so in case the users do not explicitly specify a style, we need
// to use sensible defaults.
this.setTextColor(getResources().getColor(R.color.com_facebook_loginview_text_color));
this.setTextSize(TypedValue.COMPLEX_UNIT_PX,
getResources().getDimension(R.dimen.com_facebook_loginview_text_size));
this.setPadding(getResources().getDimensionPixelSize(R.dimen.com_facebook_loginview_padding_left),
getResources().getDimensionPixelSize(R.dimen.com_facebook_loginview_padding_top),
getResources().getDimensionPixelSize(R.dimen.com_facebook_loginview_padding_right),
getResources().getDimensionPixelSize(R.dimen.com_facebook_loginview_padding_bottom));
this.setWidth(getResources().getDimensionPixelSize(R.dimen.com_facebook_loginview_width));
this.setHeight(getResources().getDimensionPixelSize(R.dimen.com_facebook_loginview_height));
this.setGravity(Gravity.CENTER);
if(isInEditMode()) {
// cannot use a drawable in edit mode, so setting the background color instead
// of a background resource.
this.setBackgroundColor(getResources().getColor(R.color.com_facebook_blue));
// hardcoding in edit mode as getResources().getString() doesn't seem to work in IntelliJ
loginText = "Log in";
} else {
this.setBackgroundResource(R.drawable.com_facebook_loginbutton_blue);
initializeActiveSessionWithCachedToken(context);
}
}
parseAttributes(attrs);
}
both style and login_text are taken under consideration now. Works fine for me.
I ended up just having to change the text in the FacebookSDK source.
The login string is com_facebook_loginview_log_in_button located in FacebookSDK/res/values/strings.xml
As a shortcut, you can change the login button text directly in FB SDK 4.0 in com.facebook.login.widget.LoginButton class->setButtonText() method
I tried many of these solutions but nothing works, finally I came to an end with :
Locale loc = Locale.FRENCH;
loginButton = (LoginButton)findViewById(R.id.fb_login_button);
loginButton.setTextLocale(loc);
This changes the text to the locale you set and also the confirm dialogs, at least what I need.
Hope this helps.

Categories

Resources