I've got the crouton library ( https://github.com/keyboardsurfer/Crouton ) working with the default layout for notifications. I would like to use a custom layout xml file for the notifications so I could set a different typeface to the TextView to match the rest of my application. I have extended a TextView to get the custom typeface working.
Browsing the source for the library, I found a couple of methods that will probably help me:
public static Crouton make(Activity activity, View customView, ViewGroup viewGroup) {
return new Crouton(activity, customView, viewGroup);
}
public static Crouton make(Activity activity, View customView) {
return new Crouton(activity, customView);
}
But I'm struggling to find good example on how to use custom layouts for crouton messages and how I would set the text/message style for them (I have defined some custom styles using Style.Builder()).
The custom layout I want to use is:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res/uk.co.volume.pinkmothballs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
<com.myapp.ui.views.TypefacedTextView
android:id="#+id/crouton_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="14sp"
android:gravity="center"
/>
</RelativeLayout>
Can someone point me in the right direction?
You can a custom Style that uses the resourceId of your text appearance via Style.Builder.setTextAppearance(...).
This takes a reference from your styles.xml and uses it within the internal TextView of the Crouton.
Then you can call Crouton.makeText or Crouton.showText with your custom Style.
Related
I am using merge tag in custom view and trying to set layout_marginTop or paddingTop on parent view, but doesn't work. Here is my code
file name: my_view.xml
<merge
android:layout_width="match_parent"
android:layout_height="match_parent"
android_layout_marginTop="17dp" > // This margin is lost!
// content here ...
</merge>
So in My custom view file, MyView.java, I just inflate this my_view.xml. But the android_layout_marginTop information is lost.
public class MyView {
private void initViews() {
View view = LayoutInflator.from(context).inflate(R.layout.my_view, this);
// get rest views
}
}
I have tried to set the margins and paddings in the code using LayoutParams, but still not working.
Your help would be much appreciated!
The <merge> tag is not a View, so trying to set a margin on it isn't going to work.
It looks like you're following the "Compound Control" pattern, where you create a subclass of some common ViewGroup (a LinearLayout, perhaps) and then inflate some other standard Views into it. If that is the case...
Remove all of the layout_ attributes from your <merge> tag, and instead place them on your custom view's tag, wherever you use it in your screen's layout. Something like this:
<com.example.stackoverflow.MyView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="17dp"
...
/>
I'm new to Android and have recently started adopting the pattern to create an auto-layout-loading custom view based on a layout file. In the layout you use the 'merge' tag as the root, then in the constructor of your view, you inflate that layout into yourself so you are essentially the root of the merged-in controls. Right after you inflate, still in the constructor, you can find the child controls from the layout and assign them to private fields in the custom class so they will always be available, even when using recycler views.
Contrast that with including a layout. In that case, the layout has to define a root element (which can be your custom control, but in that case, you would not inflate the layout into yourself and would have to move the control lookup to onFinishInflate) but otherwise it ends up with the same view hierarchy.
In short, instead of this...
<include layout="#layout/layout_myCustomControl" />
You can now do this...
<com.mydomain.MyCustomControl />
However I find the auto-loading custom control version to be much more flexible and maintainable. The advantages of the second one are not only that you can use custom attributes in the referencing XML layouts (which you can't with the 'include' version) but it also gives you a central place to manage the code as well as layout management/control lookup.
So now I can do this...
<com.mydomain.MyCustomControl
app:myCustomAttribute="Foo" />
And if the control has to have code backing up its behavior, it's nicely encapsulated in the custom view.
Here's an example layout for the auto-loading version...
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="This is static text in the header" />
<TextView android:id="#+id/dateTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</merge>
And here's the class that uses it...
public class MainHeader extends LinearLayout
{
TextView dateTextView;
public MainHeader(Context context, #Nullable AttributeSet attrs)
{
super(context, attrs);
setOrientation(VERTICAL);
LayoutInflater.from(context).inflate(R.layout.header_main, this);
dateTextView = (TextView)findViewById(R.id.dateTextView);
dateTextView.setText(<<Code for setting date goes here>>);
}
}
But what I'm wondering is if the layout is purely static in nature--say holding a static image and fixed text--is it still considered good practice to use a custom view to represent it? I'd say yes for consistency, plus should I want to extend it in the future, you're already prepared for it and have to do so in just one place regardless of how many places it's used. In contrast, if you included the layout directly in say 20 places, you may have to update all 20 (depending on what's actually changed/needed.)
Pros for the Custom View approach:
Central location for managing layout loading and control lookup
Can support backing code implicitly/internally for updating the view.
Can use attributes when being referenced in other layout files
Better encapsulation (you can hide the layout itself from the outside world exposing behaviors via direct methods)
Can simply be 'new'd' up in code and the layout will automatically load. No inflating or casting needed.
Cons for Custom View approach
When used in Layout files, you now have to also specify width and height making usage a little more verbose.
May add extra classes to your project (not always, but sometimes.)
Again, it seems to me like a no-brainer, but I'm wondering if there's a preferred 'Androidy' way, or is it just a preference up to each developer?
Such approach will add additional level in your view trees. So you only made the UI tree more complex for no good reason. From other side, you can follow next steps to get rid of that side-effect:
<merge /> can only be used as the root tag of an XML layout
when inflating a layout starting with a <merge />, you must specify a parent
ViewGroup and you must set attachToRoot to true (see the
documentation of the inflate() method)
That's it.
Well apparently what I came up with wasn't that unique after all! Here's an article explaining in detail this exact scenario, along with the pros and cons of each. Looks like they too came to the same conclusion.
TrickyAndroid: Protip. Inflating layout for your custom view
I am trying to creating a custom view extends RelativeLayout.
To avoid adding view by coding. I prepare a xml with my custom relativelayout.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android">
...
</RelativeLayout>
So in my custom view class, I would inflate the xml by
View.inflate(context, R.layout.custom_view, this);
My question is as my class is already a RelativeLayout, if I doing so, I would have two levels of RelativeLayout. Of course, I can solve it by removing the outer RelativeLayout in xml. But if I am doing so, I cannot see preview in xml editor in eclipse which is the reason I want my custom view inflate from xml.
Even my custom view class extends FrameLayout, there would be one layer more in the view hierachy. How to solve this problem?
To reduce the unnecessary extra layer, you need to use merge tags. Here is a good example on how to use it.
http://android-developers.blogspot.com/2009/03/android-layout-tricks-3-optimize-by.html
<merge xmlns:android="http://schemas.android.com/apk/res/android">
...
</merge>
I'm coming from the world of GWT and UIBinder, where I'm used to defining custom components by extending Composite, and then putting all the UI layout code in a MyComponent.ui.xml file. This is a very nice way to build up components from smaller pieces.
I'm trying to achieve the same effect on Android with custom Views. I've been able to programmatically extend View, and then add objects by calling addView(textView). I'd like to be able to do that in XML, but I don't see how to associate an xml layout file with the view (apart the primary res/layout/main.xml file, which provides the primary layout for the app.
How can I layout my custom views in XML?
Edit: My question was unclear. What I'm looking to do is associate a my_widget.xml file with my customized view. Then in my_widget.xml I'd like to define various TextViews, etc, and plug them into my View class.
Use the fully qualified name of your custom view class in place of one of the built-in views. Here's a layout, for instance, that fills the window with your class:
<?xml version="1.0" encoding="utf-8"?>
<my.package.MyCustomView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/my_view"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
To construct Views from XML, use LayoutInflater.
You can use findViewById (int id) with an id defined in XML. See the example in the android doc here (scroll down to IDs).
I understand how to create a custom Android control, and I believe I understand how to pull attributes for it from the Xml layout. I don't know, however, how to get any children elements from it.
Here's a visual example of what I'm trying to accomplish:
public class Menu extends LinearLayout
{
// Custom Code
}
public class MenuItem extends Button
{
// Custom Code
}
<!-- Layout -->
<?xml version="1.0" encoding="utf-8"?>
<Menu>
<MenuItem/>
<MenuItem/>
</Menu>
When my Menu is created, how do I get references to the two MenuItems?
You should use an android:id to do that. If you will not know how many childs you will have:
LinearLayout extends ViewGroup, so you can use getChildAt() and getChildCount() to get those views.
for accesing any control (custom or system ) an id is a must. by specifying an id you give it a unique identity. Using this id you can get a reference to that control.