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);
}
}
Related
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.
As of stated by this android developer blog post, we can now use VectorDrawables on Android API 7+ using the AppCompat 23.2.0 and later versions.
Everything seems to work fine for me, except when it comes to use drawables as a compound to a TextView.
Normally, one would do something like:
customTab.setCompoundDrawablesWithIntrinsicBounds(
0,
R.drawable.my_vector,
0,
0
);
Unfortunately this is not working at the moment, and I wasn't able to find a workaround for this problem.
As of stated by the post, the only available and working methods are the xml one, using app:srcCompat="#drawable/..." and the Java setImageResource(...)
How can I use the new vector drawable support with the setCompoundDrawable() method?
Thanks in advance.
Edit:
as requested, here's the result of the VectorDrawableCompat class:
the xml is:
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="98"
android:viewportHeight="102">
<path
android:fillColor="#4D4D4D"
android:strokeWidth="2"
android:strokeColor="#4D4D4D"
android:pathData="M63.3336386,72.2631001 C56.7778507,76.9021242
48.7563953,79.6307404
40.09319,79.6307404 C17.9503315,79.6307404 0,61.804793 0,39.8153702
C0,17.8259473 17.9503315,0 40.09319,0 C62.2360484,0 80.1863799,17.8259473
80.1863799,39.8153702 C80.1863799,50.8100816 75.6987973,60.7639242
68.4433567,67.9690887 L96.7320074,96.0617174 C98.0293966,97.3501165
97.9978616,99.4159703 96.6953405,100.709466 C95.3837385,102.011979
93.2974318,102.019264 92.0151615,100.745879 L63.3336386,72.2631001
L63.3336386,72.2631001 L63.3336386,72.2631001 Z M40.09319,74.9465792
C59.6310061,74.9465792 75.4695341,59.217802 75.4695341,39.8153702
C75.4695341,20.4129383 59.6310061,4.6841612 40.09319,4.6841612
C20.5553738,4.6841612 4.71684588,20.4129383 4.71684588,39.8153702
C4.71684588,59.217802 20.5553738,74.9465792 40.09319,74.9465792
L40.09319,74.9465792 L40.09319,74.9465792 Z" />
</vector>
Starting from support library 23.2 you can use the next solution:
Drawable drawable=AppCompatDrawableManager.get().getDrawable(mContext, R.drawable.drawable);
view.setCompoundDrawablesWithIntrinsicBounds(null, drawable, null, null);
Following the precious suggestions given by #pskink I was able to load correctly a drawable inside my view.
My problem was the selector I was using as my xml to give the "current active tab" feedback in my TabLayout.
I've solved my problem by doing a cast:
Drawable drawable;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
drawable = ContextCompat.getDrawable(mContext, tabIcons[i]);
} else {
drawable = getResources().getDrawable(tabIcons[i]);
}
StateListDrawable stateListDrawable = (StateListDrawable) drawable;
customTab.setCompoundDrawablesWithIntrinsicBounds(
null,
stateListDrawable,
null,
null
);
You can solve it by data-binding also:
create adapter method
public class Bindings {
#BindingAdapter({"bind:drawableStartId"})
public static void setDrawableStart(TextView textView, #DrawableRes int id) {
Drawable drawable = AppCompatDrawableManager.get().getDrawable(textView.getContext(), id);
Drawable drawables[] = textView.getCompoundDrawablesRelative();
textView.setCompoundDrawablesRelativeWithIntrinsicBounds(drawable, drawables[1], drawables[2], drawables[3]);
}
}
and use app:drawableStartId in your xml file.
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<import type="your.path.to.R" />
</data>
<TextView
app:drawableStartId="#{isSelected ? R.drawable.one :R.drawable.another}"
/>
<layout/>
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?
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);
I have a problem with this separator:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" >
<padding android:left="10dip" android:right="10dip"/>
<solid android:color="#color/listSeparator"/>
<size android:height="1px" />
</shape>
I'm trying to make a little margin/padding in the left/right of the listview component (using a relative on it , not a ListView Object) . Then when i try to put it this way...
getListView().setDivider(getResources().getDrawable(R.drawable.song_separator));
... it's directly ignored , putting a full layout separator .
Now i don't know what is the problem , but i know that :
I can't put a margin in all ListView , cause i want the listHeader fill_parent
I have tried to put a false border , but it isn't nice looking when i change it's background color , putting me a separator space.
Any idea?
MODIFIED
My last partial solution is to put an ImageView , aligned next to the parent bottom .
This is partial cause it puts on the bottom but not on the original divider.
If someone can tell me how to put that ImageView on the exact line of the divider, i would give him the +50 too.
Quiroga so my first bet would be to make the code more debugable by spliting the method call up into individual lines.
ListView lview = getListView();
if (lview != null){
Resources res = getResources();
if (res != null) {
Drawable dable = res.getDrawable(R.drawable.song_separator);
if (dable != null){
lview.setDivider(dable)
}
}
} else {
//Log in some way that you have a problem.
}
I know it looks kind of over complicated but that way you can make sure that the Drawable is found and is the correct one and then properly assigned to the ListView.
Another thing you can try is just assigning a different maybe platform specific separator and see if that works properly.
Also try to get your hands on the Android Source Code it is back online if you add that to your Java Project you can debug into the Platform classes and debug deep into the platform code.
So this isn't really a solution for your problem but maybe it can help you find the solution.
Put the header in a separate file and access it as:
public class AuditActivity extends ListActivity {
Budget budget;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.audit);
ListView lv = getListView();
LayoutInflater infalter = getLayoutInflater();
ViewGroup header = (ViewGroup) infalter.inflate(R.layout.header, lv, false);
lv.addHeaderView(header);
budget = new Budget(this);
/*
try {
test = budget.getTransactions();
showEvents(test);
} finally {
}
*/
// switchTabSpecial();
}
Follow this link .......it has a detailed info,use RelativeLayout instead of Linear One, I hope this will help you.
Android: Adding static header to the top of a ListActivity