android:visibility with condition delays before display - android

I'm trying to use android databinding. But I got some problem when I use android:visibility with condition. Like android:visibility="size == 0 ? View.GONE : View.VISIBLE".
When it returns false, it will show this view first, then for a while it turns to gone.
Can I fix this? Or is this the databing's bug?

I ever tried code like this
android:visibility="#{size==0?View.GONE:View.VISIBLE}",
but it can not be compiled.I don't know why, maybe it is a bug.
So I using code following instead, firstly, write a Helper.
public class Helper {
#BindAdapter("bind:attr")
public static void setAttr(View view, Object obj) {
if (someCondition(obj)){
view.doSomething();
}
}
}
secondly, using custom attr in xml file
<View
...other attrs...
app:attr="#{obj}" />
note:
the 'attr' in the annotation must be the same with 'attr' used in xml file.
the View in the static method must be the same with the View in xml file.
My Gradle version and dataBinder version
dependencies {
classpath 'com.android.tools.build:gradle:1.5.0'
classpath "com.android.databinding:dataBinder:1.+"
}
And, remove other operations unrelated on this view.
Or offer your activity code.

Related

Newbie question about Android Studio and button not syncing in main activity

Here is the tutorial
https://www.youtube.com/watch?time_continue=289&v=OGfZpfn-dGI
In my android studio it doesn't recognize the button iv'e name them
android:id="#+id/top_button"
android:text="top button"
android:text="button 2"
android: android:id="#+id/button_2"
top_button.setOnClicklistner {
println(top button was clicked)
Button_2.setOnClicklistner {
println(Button)
We're missing a lot of context here that would probably help us help you.
A few things first though:
- The android:id property in your XML layout is how you name the View in question. This is most often how you will reference the View in code.
- The android:text property is the user visible text on views like TextView.
- In order for top_button to refer to your desired View in your XML layout file, it needs to be bound in code. There's a couple of normal ways of doing it findViewById() and data-binding.
I'm going to assume, for now, that the last step is what you are missing (it seems the most likely culprit at this point)... Here's a few ways to bind it:
Method 1: when using an Activity class
If you're binding top_button to your View from an Activity class, this should work:
private lateinit var top_button // replace View here with your widget's type
fun onCreate(...) {
super.onCreate(...)
setContentView(R.layout.<i>your_layout_file_name_here</i>)
top_button = findViewById(R.id.top_button)
...
}
Method 2: when using a Fragment class
If you're binding top_button to your View from a Fragment class, it's more like this:
private lateinit var top_button: View // replace View here with your widget's type
fun onCreateView(...): View {
val rootView = layoutInflater.inflate(R.layout.<i>your_layout_file_name_here</i>)
top_button = rootView.findViewById(R.id.top_button)
...
return rootView
}
Method 3: when using data-binding
I prefer this method myself, but you should Google how to setup data-binding in Android as you'll need changes in your build.gradle and all.
First, change your XML layout to be:
<layout>
<!-- your existing layout XML here -->
</layout>
Then in your Activity/Fragment, let's say your XML layout file is named activity_my_cool_screen.xml, you can do:
val binding = ActivityMyCoolScreenBinding.inflate(getLayoutInflater())
binding.topButton.setOnClickListener(...)
Notice here that the ActivityMyCoolScreenBinding class is auto-generated for you. If it turns red at first, then first verify you've accurately setup data-binding in your project, then if that's good to go, make sure to import the ActivityMyCoolScreenBinding class. If you change your XML layout's filename, then the ActivityMyCoolScreenBinding class name will change to match automatically. But, I'd recommend if you do change the name, that you use Android Studio's refactoring/renaming tools as it'll search your codebase and update it everywhere. Otherwise, you have to do it by hand (doable, but potentially tedious and error prone).
Good luck!

Data binding passing xml element with special characters

Consider the following bindingAdapter
#BindingAdapter({"pager"})
public static void bindViewPagerTabs(final TabLayout view, final ViewPager pagerView)
{
view.setupWithViewPager(pagerView, true);
}
and the setting in the xml is :
<com.google.android.material.tabs.TabLayout
android:id="#+id/card_control_tab_layout"
style="#style/tab_in_toolbar_style"
android:background="#color/colorPrimary"
app:tabGravity="fill"
app:pager="#{(pager_r)}"
app:tabMode="scrollable" />
Gives the following error :
error: cannot find symbol class ActivityCardControlBindingImpl
But if I changed the pager Id to anything without the underscore or any special characters like #+id/pager it works perfectly, any valid reason ?
It works if you write app:pager="#{(pagerR)}" instead of app:pager="#{(pager_r)}". Also you don't need the brackets, so you could just write app:pager="#{pagerR}".
EDIT:
But if I changed the pager Id to anything without the underscore or any special characters like #+id/pager it works perfectly, any valid reason ?
I don't know about other special characters, but when you use the underscore in your view ids the snake case view ids like "pager_r" get converted by databinding to camel came variables like "pagerR". So as my original answer states, if you use #+id/pager_r you can use the variable pagerR.
I found the same answer as Janosch Pelzer's with a litte more explsnation here
Cannot refer to other View ID in Android data binding

EditTextPreference not showing numeric keyboard after migrating project to androidx

After migrating my project to AndroidX using the Migrate to AndroidX... functionality provided by Android Studio and having made changes to my dependencies accordingly to have everything running like it is supposed to, I have encountered a minor problem which I haven't been able to resolve.
To set a device number in my application I used an EditTextPreference like the following defined in my pref_screen.xml which is set in a PreferenceFragmentCompat class with
setPreferencesFromResource(R.xml.pref_screen, string):
<EditTextPreference
android:icon="#drawable/ic_perm_device_information_black_24dp"
android:inputType="number"
android:key="change_device_id"
android:maxLines="1"
android:selectAllOnFocus="true"
android:singleLine="true"
android:summary="#string/settings_device_id"
android:title="#string/pref_title_change_device_id" />
It used to show a numeric keyboard to change the value but after migrating to AndroidX it keeps showing a normal keyboard as shown in the image below. I tried changing the inputType and defining the decimals in xml but to no avail. Has something changed to set the inputType for the keyboard after migrating to AndroidX or am I missing something obvious?
android:inputType="numberDecimal"
android:digits="0123456789"
From an answer here:
https://stackoverflow.com/a/55461028/7059947
Cast your Preference to EditTextPreference and use setInputType On Bind.
This saved my day :)
EditTextPreference edpPrefernce = (EditTextPreference) pPreference;
edpPrefernce.setOnBindEditTextListener(new EditTextPreference.OnBindEditTextListener() {
#Override
public void onBindEditText(#NonNull EditText editText) {
editText.setInputType(InputType.TYPE_CLASS_NUMBER);
}
});
Google has not fixed this yet. You can use takisoft's fix for this problem:
https://bintray.com/takisoft/android/com.takisoft.preferencex%3Apreferencex/1.0.0
Add to build.gradle (project):
buildscript {
...
repositories {
maven {
url "https://dl.bintray.com/takisoft/android"
}
}
....
}
Add to build.gradle (app module):
implementation 'com.takisoft.preferencex:preferencex:1.0.0'
Change the imports in your classes and the components in your XML resources:
androidx.preference.EditTextPreference -> com.takisoft.preferencex.EditTextPreference
androidx.preference.PreferenceCategory -> com.takisoft.preferencex.PreferenceCategory
androidx.preference.PreferenceFragmentCompat -> com.takisoft.preferencex.PreferenceFragmentCompat
In your PreferenceFragmentCompat subclass, change the onCreatePreferences(...) declaration to onCreatePreferencesFix(...).
... and voila! The old parameters, like numeric and singleLine will be back and work!
[Solved]
Add to build.gradle (app module):
implementation 'androidx.preference:preference:1.1.0-rc01'

How to change background of multiple views in android simultaneously

I have created some views in xml which I am using as lines in my application. Every view has the exact same properties.
Example:
<View
android:layout_width="match_parent"
android:layout_height="2dp"
android:background="#000" />
I want to change the color of all these views simultaneously when the app opens.
Creating ids and then using findviewbyid in java for all of them would not be very efficient. What is the best way to achieve this?
I want them to have the same color all the time.
There are no XML shortcuts in Android for this since you cannot create color changing animations like you described. Now, if you want "efficiency" in terms of clean code while using Java; Take a look at Butterknife, a library that for binding views by using Java annotations in your code. It makes your code very declarative and you can avoid using findViewById, amongst other features.
Dependencies
Add to your project build.gradle file;
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
Add to your app module build.gradle file;
compile 'com.jakewharton:butterknife:8.4.0'
apt 'com.jakewharton:butterknife-compiler:8.4.0'
In the Activity (or View or Fragment)
To make Butterknife bind views we'll request it to bind our Activity, onCreate is a good place. Then we'll add fields for Butterknife to bind the views to, in this case as a List of views., although you can also bind the views one by one. Then we'll just change their background for this example.
public class MyActivity extends Activity {
#BindViews({R.id.view1, R.id.view2, R.id.view3})
List<View> views;
public void onCreate(...) {
...
setContentView(...);
Butterknife.bind(this);
for(View v : views) {
v.setBackgroundColor(ContextCompat.getColor(this, R.color.colorAccent));
}
}
}
Or if you need to distinguish between the views, instead of having them in a list;
public class MyActivity extends Activity {
#BindView(R.id.view1)
View view1;
#BindView(R.id.view2)
View view2;
#BindView(R.id.view3)
View view3;
public void onCreate(...) {
...
setContentView(...);
Butterknife.bind(this);
view1.setBackgroundColor(ContextCompat.getColor(this, R.color.color1));
view2.setBackgroundColor(ContextCompat.getColor(this, R.color.color2));
view3.setBackgroundColor(ContextCompat.getColor(this, R.color.color3));
}
}

Android + Data Binding #style

While using the new data binding api, I found that you can't bind to the "style" attribute. Compiler complains that it can't find the style. However, if I simply set the style as is, it'll find it just fine. For example:
doesn't work:
style="#{TextUtils.isEmpty(row.getSubtitle()) ? #style/SubTitle : #style/Title}"
works:
style="#style/SubTitle"
Error:
Error:Execution failed for task ':app:compileDebugJavaWithJavac'.
java.lang.RuntimeException: Found data binding errors.
****/ data binding error ****msg:Identifiers must have user defined types from the XML file. SubTitle is missing it file:/~/test/app/src/main/res/layout/row.xml loc:48:71 - 48:78 ****\ data binding error ****
The data binding unfortunately is not supported for styles:
https://code.google.com/p/android-developer-preview/issues/detail?id=2613
Although #bwhite is correct, there may be workarounds you can do. It depends what you need to conditionally change. For instance, if you want to change the font based on the condition (which I needed to do), you can do it by making a custom binding adapter.
In other words, doing something like this:
public class FontBindingAdapter {
#BindingAdapter({"bind:font"})
public static void setFont(TextView textView, String typefaceName){
Typeface typeface = ResourcesCompat.getFont(context, R.font.myfont);
// You'd probably want to actually use `typefaceName` to determine the font to use
textView.setTypeface(typeface);
}
Then in your layout, like this:
<TextView
app:font="#{some_condition ? #string/typeface_string_name_bold: #string/typeface_string_name_bold_light}"
I used this in my code, based on a great post: https://plus.google.com/+LisaWrayZeitouni/posts/LTr5tX5M9mb
I have a found a rather elegant solution for applying styles with data binding. I use the Paris library and then create binding adapters for interested views. for example:
#BindingAdapter("bindTextViewStyle")
fun TextView.bindTextViewStyle(styleResourceId: Int) {
this.style(styleResourceId)
}
and then in XML:
<TextView
app:bindTextViewStyle="#{viewModel.priceStyleResource}"
.../>
viewModel.priceStyleResource is a MutableLiveData in my view model which is set with the style resource ID.
priceStyleResource.value = R.style.QuoteDetailsHeaderItem_Up
EXTRA NOTE
You can also probably make a generic bindStyle binding adapter directly for the View class, but in that case the attribute items specifically for textviews (textColor for example) will not get applied. So up to you to find the right balance and naming.

Categories

Resources