We have in our project a keyboard with "Key" elements, this Key elements have attributes such as android:codes="119", android:keyLabel="w" and so on.
My question is how can I include an custom attribute like a "android:alternativeKeyLabel" to do something else.
This link gives a superficial explanation:
http://developer.android.com/guide/topics/ui/custom-components.html
Considering you have a CustomKeyboard that inherits from KeyboardView/View:
Create your custom properties in res/values/attrs.xml file (create the file if it does not exist):
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="custom_keyboard">
<attr name="alternative_key_label" format="string" />
</declare-styleable>
</resources>
Create a constructor in your custom component overriding default constructor that receives the attribute set because this one will be called when the layout is loaded.
public CustomKeyboard(Context context, AttributeSet set) {
super(context, set);
TypedArray a = context.obtainStyledAttributes(set,R.styleable.custom_keyboard);
CharSequence s = a.getString(R.styleable.custom_keyboard_alternative_key_label);
if (s != null) {
this.setAlternativeKeyLabel(s.toString());
}
a.recycle();
}
In your layout file, add your custom component and the link to your resources.
<Layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res/your.package.ProjectName"
.../>
...
<your.package.projectname.CustomKeyboard
android:id="#+id/my_keyboard"
...
app:alternative_key_label="F">
</your.package.projectname.CustomKeyboard>
</Layout>
For any other purpose, declaring a custom property in the XML file can be retrieve with attrs constructor parameter.
In my case I reuse a preference custom dialog, and set things like that:
<?xml version="1.0" encoding="utf-8"?>
<!-- something here -->
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
<your.package.projectname.CustomView
foo="bar"
/>
</PreferenceScreen>
Then in my class contructor:
public CustomView(Context context, AttributeSet attrs) {
String bar = attrs.getAttributeValue(null, "foo");
Log.d("CustomView", "foo=" + bar);
}
You can create custom attributes for your own classes that extend View or a subclass. The process is documented in the "Creating a View Class" section of the Android Dev Guide under the heading "Define Custom Attributes":
https://developer.android.com/training/custom-views/create-view#customattr
android:keyLabel is one of many XML attribute used by the Keyboard.Key class for each key on your keyboard. android:keyLabel is what you want to label the key with (like a "w" as in above). The attributes are pre-defined for the class. The "w" isn't but android:keyLabel is. If you could create android:alternativeKeyLabel what would you expect the class to do with it? I think maybe you should try to explain further what you are trying to accomplish.
Related
I have a layout .xml file and I want to use it frequently (20 times)within another xml file.
of course with different Initializing.i dont want to use include tags for 20 and init 20 times.Is there any way instead of add include tag for 20 times?
Then create custom view
Create custom class extending any ViewGroup like LinearLayout,RelativeLayout etc and handled your code depending on conditions.
public class YourCustomImpl extends LinearLayout {
...
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.your_common_view, this, true);
...
}
Include your custom implemented view like below
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
...
<your.domain.YourCustomImpl
android:layout_width="match_parent"
android:layout_height="?android:attr/listPreferredItemHeight"/>
</LinearLayout>
For more details there is nice tutorial
Theoretically implementation of multi culture stored in remote DB.
In Android we have the following:
<TextView
android:id="#+id/loginlabel"
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="25sp"
android:textStyle="bold"
android:layout_marginTop="5dp"
android:text="#string/login" />
And the text is using the value of the property login from the file string.xml.
Now my question: in the activity xml in the property android:text is there any way for me to call a function/method (can it even be from a static class) ?
A place that have some business logic and still returns a string.
I know that I can easily use the following type of code in my activity java file:
TextView loginlabel = (TextView) findViewById(R.id.loginlabel);
loginlabel.setText( GetMyText(R.id.loginlabel) );
But I am trying to avoid to write this a "million times" since I have several activities and hundreds of values on my strings.xml.
For adition information, my purpose with this is the following:
On application start I read all the string.xml and connect to my remote server (which has a DB) and verify if all the strings are inserted in that DB.
Insert the ones that are missing, with the default value of that property in string.xml.
Now, in another remote system, the client can dynamically create new cultures and translations of this properties.
back to the android, I load a list of the current cultures that we have available and also load the values (translations) from the DB. The only thing missing it to "inject" them into the place where I am using the "string" value.
This worked for me in the past.
public class MyTextView extends TextView {
public MyTextView(Context context) {
super(context);
}
public MyTextView(Context context, AttributeSet attrs) {
super(context, attrs);
setText(yourMethodWithBusinessLogic());
}
}
Don't forget to replace your normal textviews with this custom one. Press CTRL+SHFT+R for convenience.
Hope this helps.
I've implemented a custom seekbar preference, using this site - seekbar preference and it works just fine. Now I want to add values to the seekbar's customized properties from the string.xml file instead of hard-coding them:
Instead of writing customseekbar:unitsRight="Seconds" I want to have a string resource like <string name="units">Seconds</string> and use it like this: customseekbar:unitsRight="#string/units". I've tried to implement this guide. My relevant code is:
attrs.xml
<resources>
<declare-styleable name="CustomSeekBarPreference">
<attr name="unitsRight" format="reference|string"/>
</declare-styleable>
And the constructor -
CustomSeekBarPreference.java
public class CustomSeekBarPreference extends Preference implements SeekBar.OnSeekBarChangeListener {
private static final String APPLICATIONNS="http://CustomSeekBarPreference.com";
public CustomSeekBarPreference(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.CustomSeekBarPreference, 0 ,0);
mUnitsRight = a.getString(R.styleable.CustomSeekBarPreference_unitsRight);
a.recycle();
}
and the layout -
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:customseekbar="http://CustomSeekBarPreference.com" >
<com.x.sharedpreferencestestapp.CustomSeekBarPreference
android:key="1"
android:defaultValue="30"
android:max="100"
customseekbar:min="0"
android:title="Default step"
customseekbar:unitsRight="#string/units"/>
</PreferenceScreen>
But as you can see, I get 'null' instead of the right value:
Even if I change the value to a fixed string instead of string resource, like customseekbar:unitsRight="Seconds" I still get the same result. And just to make it clear - if I stick to the original code of the seekbar preference: mUnitsRight = getAttributeStringValue(attrs, APPLICATIONNS, "unitsRight", "defaultValue") it works, but not with string resource.
You're getting null for that attribute value because of the namespace you've declared for it in the layout XML - http://CustomSeekBarPreference.com.
As far as I'm aware, the obtainStyledAttributes() method can only pull attributes that are in the standard Android resource namespace – http://schemas.android.com/apk/res/android – or your app's resource namespace, which is http://schemas.android.com/apk/res/ plus the app's package name. Attributes in any other namespace will be ignored, and will not be in the returned TypedArray, which is why you get null no matter if the value is a hardcoded string, or a resource reference.
In the example you're following, they've used a similar non-standard namespace, but they're pulling the value directly from the AttributeSet, specifying that namespace in the getAttributeValue() call thereon. I can't say that I've seen this particular method often used in this manner, and the only benefit I can see to it is that it saves you from having to define your own custom attributes, which is a rather trivial task.
There are a couple of ways to fix this.
Move those layout attributes into your app's namespace, and define an attr resource for each.
This is the method demonstrated in the developer page you've linked, and is probably the most common and familiar way to implement custom View attributes.
First change the namespace declaration in the layout to:
xmlns:customseekbar="http://schemas.android.com/apk/res-auto"
(The res-auto segment is a convenience that will cause the actual namespace name to be appropriately constructed with the current package name, as previously described.)
With your posted setup, this will then cause an error with customseekbar:min, since you've not defined min as an attribute resource (attr) in your app. You can simply define that attr, and then handle it the same way you're handling unitsRight; i.e., retrieve its value from the TypedArray returned from obtainStyledAttributes(). You would do the same for any additional custom attributes you might need.
Modify the getAttributeStringValue() method in the CustomSeekBarPreference example to handle resource references as well.
This may be the simpler option, as far as modifying the given example, but directly accessing the AttributeSet values prevents those values from being adjusted for any theme or style that you might wish to apply. If that's not a concern, then the necessary changes are rather simple.
In the modified method, we just need to first check if the attribute value is a resource value, using AttributeSet#getAttributeResourceValue(). If that method returns a valid identifier, we retrieve the actual value with Resources#getString(). If not, we treat the attribute value as a plain string.
private String getAttributeStringValue(AttributeSet attrs, String namespace,
String name, String defaultValue) {
String value = null;
int resId = attrs.getAttributeResourceValue(namespace, name, 0);
if (resId == 0) {
value = attrs.getAttributeValue(namespace, name);
if (value == null)
value = defaultValue;
}
else {
value = getContext().getResources().getString(resId);
}
return value;
}
Using this method, you would not need to define your custom attributes, and the layout namespace can remain as you have it in the posted snippet.
In official android docs - there is some guidance how to use databinding in fragments and activities. However I have pretty complex picker with high ammount of settings. Something like:
class ComplexCustomPicker extends RelativeLayout{
PickerViewModel model;
}
So my question is what method of the picker I need to override to be able use binding inside it and not seting/checking individual values like textfield, etc?
And second question - how could I pass viewmodel to my picker in xml file, do I need some custom attributes for that?
I think using Custom Setters will solve your problem. Check this section in developers guidelines.
I can give you a brief example for it. Suppose the name of your view is CustomView and of your viewmodel is ViewModel, then in any of your class, create a method like this:
#BindingAdapter({"bind:viewmodel"})
public static void bindCustomView(CustomView view, ViewModel model) {
// Do whatever you want with your view and your model
}
And in your layout, do the following:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/tools">
<data>
<variable
name="viewModel"
type="com.pkgname.ViewModel"/>
</data>
// Your layout
<com.pkgname.CustomView
// Other attributes
app:viewmodel="#{viewModel}"
/>
</layout>
And from your Activity use this to set the ViewModel:
MainActivityBinding binding = DataBindingUtil.setContentView(this, R.layout.main_activity);
ViewModel viewModel = new ViewModel();
binding.setViewModel(viewModel);
Or you can directly inflate from your custom view:
LayoutViewCustomBinding binding = DataBindingUtil.inflate(LayoutInflater.from(getContext()), R.layout.layout_view_custom, this, true);
ViewModel viewModel = new ViewModel();
binding.setViewModel(viewModel);
I have been using a method to obtain color attributes from the current Context:
public static int getColorAttribute(Context context, #AttrRes int attr) {
final TypedValue value = new TypedValue();
context.getTheme().resolveAttribute(attr, value, true);
return value.data;
}
It works perfectly, but when I tried using it in my class that extends Application it returns 0. In most cases I would call the method like so:
int colorAccent = Util.getColorAttribute(this, R.attr.colorAccent);
This would return the "colorAccent" that I set in themes.xml as my AppTheme in my Manifest. But in the Application class I had to call getApplicationContext() instead of this. So I switched one of my other instances of the method in an Activity to getApplicationContext() as well and it returned 0. I also tried getApplication() and getBaseContext() with the same result.
I was wondering if there is a way to get a color from the application theme in the Application class. Or if not, why getApplicationContext().getTheme() does not seem to return the application theme.
Can you try to set the theme yourself?
getApplicationContext().getTheme().applyStyle(R.style.someTheme, true);
and then in styles have your theme that is a child of some theme you want in android. Also this method should be frowned on as themes are meant to be accessed from activity context. application context is not complete for UI tasks.