Unexpected namespace prefix app in child view of CustomLayout - android

I got the error when use attribute in child view of a CustomLayout (I have define a custom LayoutParams to allow child view use this attribute)
However, code's still RUNNING and display correct value (you can check my code below, when I run app it will display "Hello" in logcat)
Here is my code
style.xml
<declare-styleable name="CustomRelativeLayout_Layout">
<attr name="title" format="string" />
</declare-styleable>
CustomRelativeLayout class
public class CustomRelativeLayout extends RelativeLayout {
public CustomRelativeLayout(Context context) {
this(context, null);
}
public CustomRelativeLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CustomRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
return new CustomLayoutParams(getContext(), attrs);
}
#Override
public void onViewAdded(View child) {
super.onViewAdded(child);
CustomLayoutParams layoutParams = (CustomLayoutParams) child.getLayoutParams();
Log.i("TAG", "title = " + layoutParams.title);
}
final class CustomLayoutParams extends RelativeLayout.LayoutParams {
String title;
CustomLayoutParams(Context c, AttributeSet attrs) {
super(c, attrs);
TypedArray ta =
c.obtainStyledAttributes(attrs, R.styleable.CustomRelativeLayout_Layout);
title = ta.getString(R.styleable.CustomRelativeLayout_Layout_title);
ta.recycle();
}
}
}
Of course, I can disable it by add tools:ignore="MissingPrefix" but I don't like this much. Any help or suggestion would be great appreciated.
Here is my demo https://github.com/PhanVanLinh/AndroidPassAttributeToChildVIew

After many try, I found a solution for my problem
Change title to layout_title will make the error gone
<declare-styleable name="CustomRelativeLayout_Layout">
<attr name="title" format="string" />
</declare-styleable>
The magic is layout_ because the error still happened if I use like
title_, title_dasdasdsad, lo_title, title_23232

Related

Custom view (not ViewGroup) created based on xml layout (with predefined attributes)

I want to implement a custom ImageView with some predefined attributes based on the xml file. To do that I prepared a layout wrapped within merge tag:
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<ImageView
android:id="#+id/my_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="center"
android:src="#drawable/icon" />
</merge>
And extended ImageView class:
public class CustomImageView extends LinearLayout{
public ImageFormField(Context context) {
super(context);
init();
}
public ImageFormField(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
public ImageFormField(Context context, #Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public ImageFormField(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init();
}
private void init() {
View.inflate(getContext(), R.layout.custom_image_view, this);
}
}
It works so far, but I actually don't need that LinearLayout as I could extend directly from the ImageView. By extending ImageView I'd like to have the possibility to override src parameter from the default layout.
So I removed merge tag to have only ImageView in the layout and tried this:
public class CustomImageView extends AppCompatImageView{
public ImageFormField(Context context) {
super(context);
init();
}
public ImageFormField(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
public ImageFormField(Context context, #Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
View.inflate(getContext(), R.layout.custom_image_view, null); //can't pass root here
}
}
... but the image is simply not displayed. I want to be able to use my view this way:
<com.my.package.CustomImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
with possibility to override src attribute. Is there a way to do that by inflating layout or do I have to go deep with attributes (including custom ones)?
UPDATE
By "overriding src attribute I mean that by default image will have source from its xml file, but user can use it that way to pass another value within this custom view:
<com.my.package.CustomImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/another_icon" />
To provide a "default" image but also allow the user to override that default by specifying the android:src attribute, you can do this:
package com.example.stackoverflow;
import android.content.Context;
import android.support.v7.widget.AppCompatImageView;
import android.util.AttributeSet;
public class CustomImageView extends AppCompatImageView {
public CustomImageView(Context context, AttributeSet attrs) {
super(context, attrs);
if (getDrawable() == null) {
setImageResource(R.drawable.default_image);
}
}
}
Then you can use it like this:
<!-- will display `default_image` -->
<com.example.stackoverflow.CustomImageView
android:layout_width="200dp"
android:layout_height="200dp"/>
Or:
<!-- will display `other_image` -->
<com.example.stackoverflow.CustomImageView
android:layout_width="200dp"
android:layout_height="200dp"
android:src="#drawable/other_image"/>
There's no need to inflate anything inside the custom image view, and no need to create custom attributes (though you could certainly create custom attributes and use them if you wanted to).
You could update the Java code to apply other "default" styles too.

Android simple widget to show image into ImageView

i'm created simple widget extends from ImageView, in this simle code i want to set image into ImageView from layout xml,i want change background imageview image and change image to set other image into ImageView, but my problem in first time dont show image
1) i'm create new attribute into attr.xml:
<declare-styleable name="CIconButton">
<attr name="button_icon" format="integer" />
<attr name="background_icon" format="reference" />
</declare-styleable>
2) use CIconButton class into layout:
<!-- xmlns:app="http://schemas.android.com/apk/res/com.sample.app.tpro" -->
<com.sample.widget.CIconButton
android:id="#+id/imgv_update_selected_phones"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="10dp"
app:button_icon="#drawable/icon_add_action" />
3) CIconButton class
public class CIconButton extends ImageView implements OnClickListener {
private Drawable mSelectedBackground;
public CIconButton(Context context) {
super(context, null);
}
public CIconButton(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CIconButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CIconButton, defStyle, 0);
mSelectedBackground = a.getDrawable(R.styleable.CIconButton_button_icon);
setImageDrawable(mSelectedBackground);
a.recycle();
setOnClickListener(this);
}
#Override
public void onClick(View v) {
}
}
PROBLEM:
my custom widgets class dont show image set into layout xml, for example this class dont show icon_add_action from drawable
My problem resolved , i must be change second constructor as :
public CIconButton(Context context, AttributeSet attrs) {
super(context, attrs);
}
to:
public CIconButton(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
this call last this class constrctor

Android create custom NumberPicker widget

I'm using some simvot number picker in application, I want to create custom widget for that and use in all of project, now i'm create this files but I can not set any value for custom widget.
My attributes:
<declare-styleable name="CNumberPicker">
<attr name="maxValue" format="string" />
<attr name="minValue" format="string" />
<attr name="value" format="string" />
</declare-styleable>
My Custom NumberPicker widget:
public class CNumberPicker extends net.simonvt.numberpicker.NumberPicker implements OnClickListener {
private int maxValue;
private int minValue;
private int value;
public CNumberPicker(Context context) {
super(context);
}
public CNumberPicker(Context context, AttributeSet attrs) {
super(context, attrs);
processAttributeSet(attrs);
}
public CNumberPicker(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CNumberPicker, defStyle, 0);
processAttributeSet(attrs);
maxValue = Integer.parseInt(a.getString(R.styleable.CNumberPicker_maxValue));
minValue = Integer.parseInt(a.getString(R.styleable.CNumberPicker_minValue));
a.recycle();
setOnClickListener(this);
}
#Override
public void onClick(View v) {
}
private void processAttributeSet(AttributeSet attrs) {
this.setMaxValue(attrs.getAttributeIntValue(null, "maxValue", 0));
}
}
My defined widget into xml:
<com.sample.widget.CNumberPicker
android:id="#+id/np_choose_hour"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginLeft="10dp"
android:layout_weight="0.20"
android:gravity="center_horizontal"
app:maxValue="10"
app:minValue="1"
app:value="5">
</com.sample.widget.CNumberPicker>
how to set value defined into xml in layout?
You have to inflate the layout in code.
public CNumberPicker(Context context) {
super(context);
LayoutInflater.from(context).inflate(R.layout.cnumberpicker, this);
}
presuming the layout file is cnumberpicker.xml
EDIT: These 3 functions are constructors. Any one of them could be called to construct the object. By using this instead of super we can force all constructors to end up calling the 3 parameter constructor. You need some cohesion here. You don't want to copy paste code every time you make one change.
public CNumberPicker(Context context) {
this(context, null);
}
public CNumberPicker(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CNumberPicker(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CNumberPicker, defStyle, 0);
processAttributeSet(attrs);
// this method allows a default value if no attributes are given. You should use them.
maxValue = Integer.parseInt(a.getString(R.styleable.CNumberPicker_maxValue,"10"));
minValue = Integer.parseInt(a.getString(R.styleable.CNumberPicker_minValue,"0"));
a.recycle();
}

Get value of a custom attribute in Java Code

I create an attribute in attrs.xml file:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="Custom">
<attr name="src" format="integer" />
</declare-styleable>
</resource>
And in my code, I get the value of the attribute like this:
attrs.getAttributeIntValue("mynamespace", "src", -1);
It works. I get the value of 'src' from the layout xml file.
But my question is why android does not generate a value in R class so that I don't need to use the string 'src' again in my java code?
Instead use the TypedArray
public CustomView(final Context context) {
this(context, null);
}
public CustomView(final Context context,
final AttributeSet attrs) {
this(context, attrs, 0);
}
public CustomView(final Context context,
final AttributeSet attrs, final int defStyle) {
super(context, attrs, defStyle);
final TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.Custom, defStyle, 0);
int src = a.getInt(R.styleable.Custom_src, 0);
a.recycle();
}

android:how to instantiate my custom view with attributeset constructor

My custom view has dynamic custom attribute,e.g. the backgroundimage attribute,assign via current week.
I wan't to use construtor CalendarView(Context context, AttributeSet attrs) to pass several attribute,and I try to instantiate the attributeset with Xml.asAttributeSet,but it can't work. can anyone tell me how to do.
Note:my custom view has dynamic attribute ,so I don't wan't to instantiate the custom view via xml layout. my solution is incorrect ?
here is the custom view:
public class CalendarView extends View {
int backgroundImage;
public CalendarView(Context context, AttributeSet attrs) {
super(context, attrs);
backgroundImage = attrs.getAttributeResourceValue("http://www.mynamespace.com", "backgroundimage", 0);
}
}
here is the activity:
public class TestActivity extends Activity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(createTestView(0));
}
public CalendarView createTestView(int currentWeek) throws XmlPullParserException, IOException {
String attributes = "<attribute xmlns:android=\"http://schemas.android.com/apk/res/android\" " +
"xmlns:test=\"http://www.mynamespace.com\" " +
"android:layout_width=\"fill_parent\" android:layout_height=\"30\" " +
"test:backgroundimage=\"#drawable/"+ currentWeek +"_bg" + "\"/>";
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
factory.setNamespaceAware(true);
XmlPullParser parser = factory.newPullParser();
parser.setInput(new StringReader(attributes));
parser.next();
AttributeSet attrs = Xml.asAttributeSet(parser);
return new CalendarView(this,attrs);
}
}
You have to declare the attribute as styleable on attr.xml file located in values the
for example:
<declare-styleable name="yourView">
<attr name="aAttr" format="dimension" />
<attr name="bAttr" format="dimension" />
>
After that you have to use them as this in your custom view, and you must declare both default constructors:
public CalendarView(Context context) {
super(context);
}
public CalendarView(Context context, AttributeSet attrs) {
super(context, attrs);
backgroundImage = attrs.getAttributeResourceValue("http://www.mynamespace.com",
"backgroundimage", 0);
int typefaceIndex = attrs.getAttributeIntValue("http://schemas.android.com/apk/res/android", "typeface", 0);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.yourView);
}
This should work, to get parameters for your custom view. Feel free to ask if you don't undersand.
the typeFaceindex is just an example which works.
After that you have to use your customView into layout like any other this:
<com.example.yourView> </com.example.yourView>
Maybe I don't get what you are doing or why you're doing it, but I find your attempt with the AttributeSet quite complicated.
I'd suggest you create another constructor like this
public CalendarView(Context context, int backgroundRessourceID) {
super(context);
setBackgroundResource(backgroundRessourceID);
}
And then instantiate your CalendarView like this
CalendarView cv = new CalendarView(this, R.drawable.0_bg);
cv.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, 30));
Hopefully this solved your issue ...

Categories

Resources