android:how to instantiate my custom view with attributeset constructor - android

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 ...

Related

Unexpected namespace prefix app in child view of CustomLayout

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

Pass data to custom View class

I want to pass some data to a custom class that extends android.view.View.
However, I get a warning message saying that :
Custom view LinePlot is missing constructor used by tools: (Context)
or (Context,AttributeSet) or (Context,AttributeSet,int)
However, I run the code and all seems to work smoothly.
What is happening?
How should I pass my data to my class?
Why can't I use a custom constructor?
Thanks!
import android.graphics.Canvas;
import android.graphics.Paint;
import android.view.View;
import java.util.ArrayList;
public class LinePlot extends View {
private ArrayList<Float> mPoints;
private int dx;
private int dy;
Paint paint=new Paint();
public LinePlot(Context context,int dx_plot, int dy_plot, ArrayList<Float> points) {
super(context);
mPoints=points;
dx=dx_plot;
dy=dy_plot;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// plotting my data here
}
}
so a couple of steps have to followed here -
(i) in values/attrs.xml add the following code -
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="NinjaView">
<attr name="addButtonBackgroundDrawable" format="integer"/>
</declare-styleable>
</resources>
(ii) call your custom view in you layout.xml file. For e.g. -
<com.example.act.ui.utils.NinjaView
android:id="#+id/ninja_view_product_desc"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
custom:addButtonBackgroundDrawable="#drawable/add_button_back_about_product"/>
(Don't forget to declare your custom namespace : xmlns:custom="http://schemas.android.com/apk/res-auto")
(iii) In your custom view's class you'll have to add a couple of things. Example -
public class NinjaView extends LinearLayout {
#BindView(R.id.button_add_to_cart_product) Button mAddToCart;
public NinjaView(Context context) {
super(context);
initializeNinjaView(context);
}
public NinjaView(Context context, AttributeSet attrs) {
super(context, attrs);
initializeNinjaView(context);
setAddButtonBack(context, attrs);
}
public NinjaView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initializeNinjaView(context);
setAddButtonBack(context, attrs);
}
private void initializeNinjaView(Context context) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.ninja_view, this);
}
#Override
protected void onFinishInflate() {
super.onFinishInflate();
ButterKnife.bind(this);
}
private void setAddButtonBack(Context context, AttributeSet attrs) {
TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs, R.styleable.NinjaView, 0, 0);
Drawable backgroundDrawable;
try {
backgroundDrawable = typedArray.getDrawable(R.styleable.NinjaView_addButtonBackgroundDrawable);
} finally {
typedArray.recycle();
}
if (backgroundDrawable != null) {
(findViewById(R.id.button_add_to_cart_product)).setBackground(backgroundDrawable);
}
}
The warning means you won't be able to use your custom view in any xml layout.
If you are not intended to do that it's still good to implement those constructors for your custom view like this:
CustomView(Context ctx) {
super(ctx)
}
Any additional attributes are normally passed as custom attributes not as constructor parameters. Read on custom view attribytes in the docs or elsewhere http://www.tutorialspoint.com/android/create_custom_attributes_for_custom_component.htm
In your LinePlot class add constructors:
public LinePlot(Context context) {
super(context);
}
public LinePlot(Context context, AttributeSet attrs) {
super(context, attrs);
}
you need to add constructors with parameters
(Context), (Context,AttributeSet) and (Context,AttributeSet,int)

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

It is possible to pass a Class<> object in Android Layout XML?

I am building a custom View that requires as one of its Attributes a Class<> object to an entity. While I made it work programmatically by adding a Setter for it, I was wondering if there is any good way to allow adding it to the XML for the layout as well?
There does not appear to be a format option for a styleable with type "class". I could use a String, but then I'd have to gamble that the value is actually a valid Class and I'd lose type hinting, so it'd not be ideal.
Is there any good way to make this work, or should I just stick with setting it programmatically?
Method 1 (With warnings):
Generic CustomView:
public class CustomView<T> extends View {
private List<T> typedList = new ArrayList<T>();
public CustomView(Context context) {
this(context, null);
}
public CustomView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CustomView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public void addTypedValue(T object){
typedList.add(object);
}
public T getTypedValue(int position){
return typedList.get(position);
}
}
Activity:
//unsafe cast!
CustomView<String> customViewGeneric = (CustomView<String>) findViewById(R.id.customView);
customViewGeneric.addTypedValue("Test");
String test = customViewGeneric.getTypedValue(0);
XML:
<org.neotech.test.CustomView
android:id="#+id/customView"
android:layout_width="wrap_content"
android:layout_height="match_parent" />
Method 2 (No warnings, safe!):
This method uses a generic CustomView. And for each type that will be used in xml you will need to create a specific class.
I have added an example implementation:
Generic CustomView: (Do not inflate this one in xml):
public class CustomView<T> extends View {
private List<T> typedList = new ArrayList<T>();
public CustomView(Context context) {
this(context, null);
}
public CustomView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CustomView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public void addTypedValue(T object){
typedList.add(object);
}
public T getTypedValue(int position){
return typedList.get(position);
}
}
XML inflatable view for the String type:
public class CustomViewString extends CustomView<String> {
//ADD Constructors!
}
XML inflatable view for the Integer type:
public class CustomViewInteger extends CustomView<Integer> {
//ADD Constructors!
}
Activity:
CustomViewString customViewString = (CustomViewString) findViewById(R.id.customViewString);
CustomView<String> customViewGeneric = customViewString;
XML:
<org.neotech.test.CustomViewString
android:id="#+id/customViewString"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<org.neotech.test.CustomViewInteger
android:id="#+id/customViewInteger"
android:layout_width="match_parent"
android:layout_height="wrap_content" />

Android: custom view from inflated layout

I am creating my own layout based on RelativeLayout as a class in code
I have basics of the layout defined in XML R.layout.menu_layout (style, drawable for background, margin, height)
If I would not need a class then I would call inflater to do this:
RelativeLayout menuLayout = (RelativeLayout)inflater.inflate(R.layout.menu_layout, root);
But I would like to be calling my own class instead
MenuLayout menuLayout = new MenuLayout(myparams);
Since I need to create a class I need to somehow inherit the R.layout.menu_layout in constructor, how can I do that? I guess there is no this.setLayout(res); or this.setResource(res); in View. Maybe I can use the other two parameters in View constructor but I did not find any tutorial how to do that either.
public class MenuLayout extends RelativeLayout {
public MenuLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initView(context);
}
public MenuLayout(Context context, AttributeSet attrs) {
super(context, attrs);
initView(context);
}
public MenuLayout(Context context) {
super(context);
initView(context);
}
private void initView(Context context) {
View view = LayoutInflater.from(context).inflate(R.layout.menu_layout, null);
addView(view);
}
}
now you can use
MenuLayout menuLayout = new MenuLayout(myparams);
you can change constructors for params i think

Categories

Resources