I would like some of my preferences to have icons, like the Settings app.
I guess one way of doing this would be to copy all the relevant code and resources from the Settings app, but it seems like overkill for a couple of icons.
Also I don't like the idea of having to duplicate the code and resources in each project that requires settings icons.
Has anyone solved this already with a simpler or resource-free approach?
The Settings application uses a private custom PreferenceScreen subclass to have the icon -- IconPreferenceScreen. It is 51 lines of code, including the comments, though it also requires some custom attributes. The simplest option is to clone all of that into your project, even though you do not like that.
source code
Since API level 11 you can add icon to preferences:
http://developer.android.com/reference/android/preference/Preference.html#setIcon%28int%29
http://developer.android.com/reference/android/preference/Preference.html#attr_android:icon
For older Android versions, you have to use custom layouts and bind images in code, as #roger-l suggests.
Updated.... answered and working
Use a custom layout for the icon preference
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+android:id/widget_frame"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
android:gravity="center_vertical"
android:paddingRight="?android:attr/scrollbarSize">
<ImageView
android:id="#+id/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="6dip"
android:layout_marginRight="6dip"
android:layout_gravity="center" />
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="2dip"
android:layout_marginRight="6dip"
android:layout_marginTop="6dip"
android:layout_marginBottom="6dip"
android:layout_weight="1">
<TextView android:id="#+android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceLarge"
android:ellipsize="marquee"
android:fadingEdge="horizontal" />
<TextView android:id="#+android:id/summary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#android:id/title"
android:layout_alignLeft="#android:id/title"
android:textAppearance="?android:attr/textAppearanceSmall"
android:maxLines="2" />
</RelativeLayout>
</LinearLayout>
and the imported class for IconPreferenceScreen
public class IconPreferenceScreen extends Preference {
private final Drawable mIcon;
private static String mType;
public IconPreferenceScreen(Context context, AttributeSet attrs, int iconRes) {
this(context, attrs, 0, iconRes);
}
public IconPreferenceScreen(Context context, AttributeSet attrs,
int defStyle, int iconRes) {
super(context, attrs, defStyle);
setLayoutResource(R.layout.preference_icon);
mIcon = context.getResources().getDrawable(iconRes);
}
public IconPreferenceScreen(Context context, int iconRes) {
this(context, null, iconRes);
}
#Override
public void onBindView(View view) {
super.onBindView(view);
ImageView imageView = (ImageView) view.findViewById(R.id.icon);
if (imageView != null && mIcon != null) {
imageView.setImageDrawable(mIcon);
}
}
}
then you can just use a new IconPreferenceScreen in place of a Preference, and add an icon
Android 3.x Honeycomb shows icons defined in standard Preferences.
So probably the use of icon depends on Android OS version or screen size.
Related
I use this kind of ViewGroup:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="#+id/icon"
android:layout_width="16dp"
android:layout_height="16dp"
android:src="#drawable/icon1"/>
<TextView
android:id="#+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/text1"/>
<TextView
android:id="#+id/data"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
I must use 2 such layouts In my fragment, but with different icon and title. Is there some way to implement it without copy/paste and RecyclerView?
There are several ways to deal with it.
1. Use the include tag.
1.1. Move LinearLayout to a separate file.
1.2 Add layout using the include tag two times with different ids:
<LinearLayout ...>
<include layout="#layout/your_layout" android:id="#+id/first" />
<include layout="#layout/your_layout" android:id="#+id/second" />
</LinearLayout>
1.3 Set content programmatically:
View first = findViewById(R.id.first);
first.findViewById(R.id.date).setText("05/05/2020");
View second = findViewById(R.id.second);
second.findViewById(R.id.date).setText("04/04/2020");
2. Implement a custom view.
There are two ways also. The first is to inflate layout inside FrameLayout. The second is to extend LinearLayout and add content programmatically. I'll show you the first one.
public class YourCustomView extends FrameLayout {
public MyView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
inflate(context, R.layout.your_custom_view_layout, this);
}
public MyView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MyView(Context context) {
this(context, null);
}
public void setContent(int iconRes, int titleRes, String data) {
findViewById(R.id.icon).setDrawableRes(iconRes);
findViewById(R.id.title).setDrawableRes(titleRes);
findViewById(R.id.data).setText(data);
}
}
3. Just copy-paste it :)
As I see icon and title are static and only data content changes, so it is not worth it to reuse such a simple layout, IMO.
i make a custom LinearLayout, xml error has occurred
this code is xamarin(C#) code, but xml code is like a Java. write the code.
Android.Views.InflateException: Binary XML file line #1: Error inflating class com.eappandroid.phone1.OpendCheckLinearLayout
first, Unhandled Exception line is (in LeftDrawerMenuItemAdapter class)(in GetView)
convertView = ((Activity)Context).LayoutInflater.Inflate(Resource.Layout.LeftDrawerMenu_List_Item, null);
LeftDrawerMenu_List_Item xml
<?xml version="1.0" encoding="utf-8"?>
<com.eappandroid.phone1.OpendCheckLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="52dp"
android:background="#drawable/menu_item_background_color_pressed"
android:minHeight="25px"
android:minWidth="25px"
android:id="#+id/left_drawer_list_item_layout"
android:orientation="horizontal">
<ImageView
android:id="#+id/left_drawer_list_icon"
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_gravity="center"
android:layout_marginLeft="12dp"
android:gravity="center" />
<TextView
android:id="#+id/left_drawer_list_item_text"
android:layout_width="wrap_content"
android:layout_height="52dp"
android:gravity="left|center"
android:layout_gravity="center"
android:layout_marginLeft="8dp"
android:layout_weight="1"
android:text="item"
android:textColor="#drawable/menu_item_title_color_pressed"
android:textSize="16sp"
android:textStyle="bold" />
<ImageView
android:id="#+id/left_drawer_noti_alert"
android:layout_width="22dp"
android:layout_height="22dp"
android:layout_gravity="center"
android:layout_marginRight="18dp"
android:background="#drawable/menu_icon_noti_new_alert"
android:gravity="center" />
</com.eappandroid.phone1.OpendCheckLinearLayout>
OpendCheckLinearLayout class
namespace EAppAndroid.Protype.LeftDrawerMenu2
{
public class OpendCheckLinearLayout : LinearLayout
{
private static readonly int[] STATE_MENU_OPEND = { Resource.Attribute.state_menu_opend };
public bool menuOpen = false;
public OpendCheckLinearLayout(Context context)
: base(context, null)
{
}
public OpendCheckLinearLayout(Context context, Android.Util.IAttributeSet attributeSet)
: base(context, attributeSet)
{
}
public OpendCheckLinearLayout(Context context, Android.Util.IAttributeSet attributeSet, int defStyle)
: base(context, attributeSet, defStyle)
{
}
protected override int[] OnCreateDrawableState(int extraSpace)
{
if (menuOpen)
{
int[] drawableStates = base.OnCreateDrawableState(extraSpace + 1);
MergeDrawableStates(drawableStates, STATE_MENU_OPEND);
return drawableStates;
}
else
{
return base.OnCreateDrawableState(extraSpace);
}
}
public void setMenuOpen(bool menuOpen)
{
if (this.menuOpen != menuOpen)
{
this.menuOpen = menuOpen;
}
}
}
}
Thanks for the help
Your namespace seems to be wrong.
You put com.eappandroid.phone1.OpendCheckLinearLayout in your xml, but in your OpendCheckLinearLayout class you have EAppAndroid.Protype.LeftDrawerMenu2, so you should probably put com.eappandroid.Protype.LeftDrawerMenu2.OpendCheckLinearLayout
EDIT:
Seems that only the namespace is required in the xml, so you should put eappandroid.Protype.LeftDrawerMenu2.OpendCheckLinearLayout
Actually, the inflate exception is not actually the problem, but it really comes from another deeper issue in your layout that is then wrapped in an InflateException. A common issue is an out of memory exception when trying to inflate an ImageView loading a drawable resource. If one of this resources has a high pixel resolution it would take a lot of memory causing then an inflate exception.
So basically, verify that the pixel resolution in your drawables images are just the minimum necessary for your layout. It helped me many times.
I hope it'll work for you too.
I'm trying to create a re-usable control that I can just add whereever I like with already existing controls so I need no attributes, need nothing to add.
I just want the control to show up my Visual Editor when I drag the "Custom View" to the Layout.
I have a simple view_textseek.xml as example Layout that I don't want to recreate everytime I want "Text and a Seekbar" in case I use it on 3 different places (for example: a colorpicker later). Or just a control with both a "TextView" and a "SeekBar"
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<TextView
android:id="#+id/view_textseek_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:paddingLeft="15dp"
android:paddingTop="10dp"
android:paddingBottom="10dp"
android:text="#string/view_textseek_text"
android:textAppearance="?android:attr/textAppearanceMedium" />
<RelativeLayout
android:id="#+id/view_textseek_container_seekbar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="#+id/view_textseek_text"
android:paddingLeft="10dp"
android:paddingTop="10dp"
android:paddingRight="10dp"
android:paddingBottom="5dp" >
<SeekBar
android:id="#+id/view_textseek_seekbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:max="255"
android:progress="0" />
</RelativeLayout>
</RelativeLayout>
and this is basically my class:
import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.widget.RelativeLayout;
public class TextSeekView extends RelativeLayout
{
public TextSeekView(Context context) { super(context); init(context); }
public TextSeekView(Context context, AttributeSet attrs) { super(context, attrs); init(context); }
public TextSeekView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(context); }
protected void init(Context context)
{
if (!isInEditMode())
{
LayoutInflater layoutInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
layoutInflater.inflate(R.layout.view_textseek, this, true);
}
}
}
As you can see, I just want to "collect" multiple already existing controls and have one "View" or "Control" to handle these. It does not show up in the editor.
Or is this due to the some old type of idiotic bug that you have to restart your environment for "custom" Views to be loaded correctly?
And I need no special attributes on my other views, nothing at all and I just want to be able to show this layout again and again when adding it, or any other layout.
Like C#, add 3 textboxes to a control just cause you use 3 textboxes each time. Then, drag that control out on the Form whenever you want 3 textboxes - nothing more to it!
Change this code:
protected void init(Context context) {
LayoutInflater layoutInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
layoutInflater.inflate(R.layout.view_textseek, this, true);
if (!isInEditMode()) {
// isInEditMode returns true when you show a view on graphical editor. Returns false while showing on running app.
}
}
is it possible to access programmatically a layout which is set to a Preference?
Here is what I have, a very simple project - proof of concept
The Preference Activity:
package com.example;
import android.os.Bundle;
import android.preference.PreferenceActivity;
import android.util.Log;
import android.view.View;
public class PreferenceExampleActivity extends PreferenceActivity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
ImageView v = (ImageView) findViewById(R.id.iconka);
}
}
The resource XML:
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
android:key="settings">
<PreferenceCategory
android:title="Category Setting Name"
android:order="1"
android:key="Main">
<Preference
android:order="1"
android:title="Setting"
android:summary="Setting1"
android:layout="#layout/profile_preference_row"
android:key="profile" />
</PreferenceCategory>
</PreferenceScreen>
The custom layout for the Preference:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#android:id/widget_frame"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
android:gravity="center_vertical"
android:paddingRight="?android:attr/scrollbarSize">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="15dip"
android:layout_marginRight="6dip"
android:layout_marginTop="6dip"
android:layout_marginBottom="6dip"
android:layout_weight="1">
<TextView android:id="#+android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceLarge"
android:ellipsize="marquee"
android:fadingEdge="horizontal" />
<TextView android:id="#+android:id/summary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#android:id/title"
android:layout_alignLeft="#android:id/title"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorSecondary"
android:maxLines="4" />
</RelativeLayout>
<ImageView
android:id="#+id/iconka"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
/>
</LinearLayout>
What I want is to be able to access the "iconka" ImageView from the Activity and change the image from there. I am using API 8 (Android 2.2)
Currently the "v" is null and I don't have any idea why is that.
A hint will be much appreciated!
Update - The Solution:
Actually, I needed a custom preference which I can modify for my needs. This one is a practical guide how to create your own Custom preference in your project:
Android & Amir - Android Preferences
See the part when the author creates a custom preference class.
After 20 min of hair pulling I found an elegant solution to this problem. First, extend the preference, then override the getView(View convertView, ViewGroup parent) method. My case was this: I had a preference layout with app icon and 2 text views(app name and version). I want to change app version programatically. How do I do this? just take a look below:
public class AboutUsPreference extends Preference {
public AboutUsPreference(Context context) {
super(context);
}
public AboutUsPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
public AboutUsPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
public View getView(View convertView, ViewGroup parent) {
View v = super.getView(convertView, parent);
((TextView)v.findViewById(R.id.textView2)).setText(getAppVersion());
return v;
}
private String getAppVersion(){
PackageInfo pInfo = null;
try {
pInfo = getContext().getPackageManager().getPackageInfo(getContext().getPackageName(), 0);
} catch (NameNotFoundException e) {
Log.e(getClass().getName(), e.getMessage(), e);
return "";
}
String version = pInfo.versionName;
return getContext().getString(R.string.version, version);
}
}
The solution is this: View v = super.getView(convertView, parent); when overriding getView method. super.getview call will return your layout view.
And my xml preference looks like:
<com.audioRec.android.settings.aboutUs.AboutUsPreference
android:layout="#layout/about_preference_layout"/>
Try taking a look at the following discussions on imageview. Might help you with your issue.
Android: findViewById of an ImageView (custom adapter)
Android : getting NullPointerException for ImageView imag = (ImageView) findViewById(R.id.image)
try getLayoutResource to get the View of the preference and then get your ImageView
I want to set the font for my application. The font is like "JOURNAL".
But the problem is, i don't know how to integrate it in to myapplication. and if i integrate it then would it be for all the application or for only the selected application? because I want it to be set just for only one application. not for all.
So for that what should i have to do ?
I have seen here. but i think it is for only TextView and not for whole application font.
So, Is there anything i have to do in manifest file ??? or what else i have to do ??
Please help me regarding it.
I agree to #Kheldar statement. There is no method to change the font in an Android app. Try this code to avoid calling a set method each time you want to change the font of an element.
public class MyTextView extends TextView {
Context context;
String ttfName;
public MyTextView(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
for (int i = 0; i < attrs.getAttributeCount(); i++) {
this.ttfName = attrs.getAttributeValue("http://schemas.android.com/apk/res/com.package.my", "ttf_name");
init();
}
}
private void init() {
Typeface font = Typeface.createFromAsset(context.getAssets(), ttfName);
setTypeface(font);
}
#Override
public void setTypeface(Typeface tf) {
super.setTypeface(tf);
}
}
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:package="http://schemas.android.com/apk/res/com.package.my"
android:id="#+id/container"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ImageView
android:id="#+id/icon"
android:layout_width="15dp"
android:layout_height="15dp"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:layout_marginRight="10dp" />
<com.package.my.MyTextView
android:id="#+id/label"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_toRightOf="#+id/icon"
package:ttf_name="My-font.otf" />
</RelativeLayout>
You cannot modify the fonts system-wide from an application (at least, as far as I know and barring some exploit).
Study this link: http://mobile.tutsplus.com/tutorials/android/customize-android-fonts/