I want to create a Compound view which consists of an ImageView a TextView and an EditText
I found this lovely tutorial on how to do that, and my compound view looks great
Now I want to copy all the properties a TextView has , all the properties the EditText has and all the properties the ImageView
so that i can style them via xml inside my custom view.
<declare-styleable name="MyCustomView">
<attr name="mcv_label" format="string" />
<attr name="mcv_fieldText" format="string" />
<attr name="mcv_fieldHint" format="string" />
<attr name="mcv_label_id" format="reference" />
<attr name="mcv_field_id" format="reference" />
</declare-styleable>
And am of course able to define them in xml
the point is I want to do
<com.lenabru.myapp.widget.MyCustomView
style="#style/tableRowStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
mcv:mcv_label_id="#+id/tvLabel"
android:text="#string/someText" <=== this line
/>
without aliasing all the properties into mcv stylable
is it possible to do ?
MyCustomView.java
public class MyCustomView extends TableRow{
private EditText editText;
private TextView label;
private ImageView image;
private int labelId;
private int formFieldId;
public FormField(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
initAttributes(context,attrs, 0);
}
public FormField(Context context) {
super(context);
initAttributes(context,null, 0);
}
private void initAttributes(Context context, AttributeSet attrs, int defStyle) {
LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.form_field, this,true);
label = (TextView)findViewById(R.id.label);
editText = (EditText)findViewById(R.id.editText);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.FormField, defStyle, 0);
if(a.hasValue(R.styleable.MyCustomView_mvc_label_id)) {
labelId = a.getResourceId(R.styleable.FormField_ff_label_id, 0);
if(labelId!=0) {
label.setId(labelId);
}
}
a.recycle();
}
}
Related
this is the preview
this is the preview links
and my layout code is below
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.asop.MainActivity">
<TextView
android:id="#+id/tv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="这是一段测试文字"
android:textSize="20sp" />
<com.asop.MixedTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
app:text1="这是一段测试文字"
app:text1size="20sp" />
as you see,here is two textView with same text and same textSize,but it shows different in textsize,l dont understand why,who can give me a explain,thank.if
there is errors in MixedTextView ,please give me the right code thanks.
below is the code of MixedTextView
public class MixedTextView extends LinearLayout {
private static final int TEXTSIZE = 16;
private static final int TEXTCOLOR = R.color.normal;
private static final int DEVIDER_LENGTH = 5;
private String text1;
private String text2;
private int text1Color;
private int text2Color;
private int text1Size;
private int text2Size;
private int deviderLength;
private TextView tv1, tv2;
public MixedTextView(Context context) {
this(context, null);
}
public MixedTextView(Context context, #Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public MixedTextView(Context context, #Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.MixedTextView);
text1 = ta.getString(R.styleable.MixedTextView_text1);
text2 = ta.getString(R.styleable.MixedTextView_text2);
text1Size = ta.getDimensionPixelSize(R.styleable.MixedTextView_text1size, TEXTSIZE);
text2Size = ta.getDimensionPixelSize(R.styleable.MixedTextView_text2size, TEXTSIZE);
text1Color = ta.getColor(R.styleable.MixedTextView_text1color, getResources().getColor(TEXTCOLOR));
text2Color = ta.getColor(R.styleable.MixedTextView_text2color, getResources().getColor(TEXTCOLOR));
deviderLength = ta.getDimensionPixelSize(R.styleable.MixedTextView_deviderLength, DEVIDER_LENGTH);
ta.recycle();
initView(context);
}
private void initView(Context context) {
tv1 = new TextView(context);
tv1.setSingleLine();
tv1.setText(text1);
tv1.setTextSize(text1Size);
tv1.setTextColor(text1Color);
tv2 = new TextView(context);
tv2.setSingleLine();
tv2.setText(text2);
tv2.setTextSize(text2Size);
tv2.setTextColor(text2Color);
View devider = new View(context);
LinearLayout.LayoutParams deviderParams = new LinearLayout.LayoutParams(deviderLength, 1);
if (getOrientation() == VERTICAL)
deviderParams = new LinearLayout.LayoutParams(1, deviderLength);
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
addView(tv1, layoutParams);
addView(devider, deviderParams);
addView(tv2, layoutParams);
}
<declare-styleable name="MixedTextView">
<attr name="text2" format="string" />
<attr name="text1" format="string" />
<attr name="text1color" format="color|reference" />
<attr name="text2color" format="color|reference" />
<attr name="text1size" format="dimension|reference" />
<attr name="text2size" format="dimension|reference" />
<attr name="deviderLength" format="dimension|reference" />
</declare-styleable>
Verified by practice,the correct answer is in comment list 5:
The setTextSize() method expects the argument to be in scaled pixels (sp), but l passed straight pixels. so here l need to
Change the setTextSize() calls to setTextSize(TypedValue.COMPLEX_UNIT_PX, size) in MixedTextView, thanks #Mike M
The reason is your text style or font style for both the text is different.The one is TextView and the other one is com.asop.MixedTextView. I hope you get my point.
I am trying to use two properties from attrs.xml such as: content and handle. When I use them while building the layout the view goes away. I have been trying the bug for 3 days and nothing worked.
Help is much appreciated!
Code in Context
<hh.hhh.app.android.hhhh.widget.ExpandablePanel
android:id="#+id/expandablePanel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
app:handle="#+id/expandButton"
app:content="#+id/listViewProduct"
app:collapsedHeight="50dip"
app:animationDuration="25">
<ListView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/listViewProduct"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/expandButton"/>
</hh.hhh.app.android.hhhh.widget.ExpandablePanel>
attrs.xml code
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="ExpandablePanel">
<attr name="handle" format="reference" />
<attr name="content" format="reference" />
<attr name="collapsedHeight" format="dimension"/>
<attr name="animationDuration" format="integer"/>
</declare-styleable>
</resources>
I am sharing my own custom class as an example. So for all custom function you need to first check if it is in EditMode or not. isInEditMode() tells us is the layout is being render by IDE preview or by phone. IDE preview is not so much powerful to run our custom codes, so it is recommended to do not run our custom while rendering by preview. I am attaching my custom class to just understand the exact scenario.
public class DynamicImageView extends ImageView {
static DynamicImageTypeListener masterImageTypeListener;
DynamicImageTypeListener imageTypeListener;
int imageResourceArray;
public DynamicImageView(Context context, AttributeSet attr, int defStyle) {
super(context, attr, defStyle);
initValues(attr, defStyle);
}
public DynamicImageView(Context context, AttributeSet attr) {
super(context, attr);
initValues(attr, 0);
}
public DynamicImageView(Context context) {
super(context);
}
public static void setMasterImageTypeListener(DynamicImageTypeListener masterImageTypeListener) {
DynamicImageView.masterImageTypeListener = masterImageTypeListener;
}
public void setImageTypeListener(DynamicImageTypeListener imageTypeListener) {
this.imageTypeListener = imageTypeListener;
}
private void initValues(AttributeSet attr, int defStyle) {
if (!isInEditMode()) { //This code will run only on phone not by preview.
TypedArray a = getContext().obtainStyledAttributes(attr, R.styleable.DynamicImageView, defStyle, 0);
imageResourceArray = a.getResourceId(0, 0);
updateImage();
a.recycle();
}
}
public void updateImage() {
TypedArray imgs = getResources().obtainTypedArray(imageResourceArray);
int imageIndex = imageTypeListener != null ? imageTypeListener.getImageType(getContext()) : (masterImageTypeListener != null ? masterImageTypeListener.getImageType(getContext()) : 0);
setImageResource(imgs.getResourceId(imageIndex, -1));
}
}
Hope it will help :)
I am having trouble understanding how to instantiate a custom layout in code. Specifically I do not know how to define the required AttributeSet parameter.
I have gone through the official docs but could not wrap my head around it :
http://developer.android.com/training/custom-views/create-view.html
http://developer.android.com/reference/android/util/AttributeSet.html
In my activity, i instantiate it with :
new MyCustomLayout(getActivity(), attrs)
But how do i define attrs?
MyCustomLayout.java
public class MyCustomLayout extends LinearLayout implements
OnClickListener {
...
...
public MyCustomLayout(Context context, AttributeSet attrs) {
super(context, attrs);
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.mycustomxmllayout, this, true);
...
}
...
}
mycustomxmllayout.xml
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android" >
<TextView
android:id="#+id/txt_1"
android:layout_width="60dp"
android:layout_height="wrap_content"
android:layout_weight="2"
android:lines="1"/>
<Button
android:id="#+id/btn_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minHeight="0dp"
android:minWidth="0dp"
android:background="#null"
android:text="x"
android:layout_weight="1"
/>
</merge>
Firstly, you should define your custom attributes in the res/values/attrs.xml, just add <declare-styleable>, for example:
<declare-styleable name="MyCustomLayout">
<attr name="showText" format="boolean" />
<attr name="buttonPosition" format="enum">
<enum name="left" value="0"/>
<enum name="right" value="1"/>
</attr>
</declare-styleable>
Now you can set your custom attrs via xml, like this:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res-auto">
<your.package.name.MyCustomLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
custom:showText="true"
custom:buttonPosition="left" />
</LinearLayout>
And in your constructor you can grab that attrs:
public MyCustomLayout(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.getTheme().obtainStyledAttributes(
attrs,
R.styleable.MyCustomLayout,
0, 0);
try {
mShowText = a.getBoolean(R.styleable.MyCustomLayout_showText, false);
mButtonPos = a.getInteger(R.styleable.MyCustomLayout_buttonPosition, 0);
} finally {
a.recycle();
}
}
If you want to set your attrs programmatically, you should create public getters/setters for that:
private boolean mShowText;
private Integer mButtonPos;
public void setButtonPos(int pos) {
mButtonPos = pos;
}
public void setShowText(boolean showText) {
mShowText = showText;
}
After that you can set your attrs programmatically:
MyCustomLayout layout = new MyCustomLayout(getActivity());
layout.setButtonPos(0);
layout.setShowText(true);
I would like to make a custom view with own xml attributes. I would like to specify a header layout that will be inflated in my custom xml view, something like this:
<com.example.MyCustomWidget
android:layout_width="match_parent"
android:layout_height="match_parent"
app:headerLayout="#layout/my_header"
/>
Is that possible and how to i get the layout resource from TypedArray?
So at the end I would like to do something like this:
class MyCustomWidget extends FrameLayout {
public ProfileTabLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.ProfileTabLayout);
int headerLayout = a.getLayout(R.styleable.MyCustomView_headerLayout, 0); // There is no such method
a.recycle();
LayoutInflater.from(context)
.inflate(headerLayout, this, true);
}
}
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="MyCustomWidget">
<attr name="headerLayout" format="reference" />
</declare-styleable>
</resources>
First you have to make your custom field. Yo do this by adding code below to res/values/attrs.xml
<declare-styleable name="MyCustomView">
<attr name="headerLayout" format="reference" />
</declare-styleable>
Then in your custom view you can get this value in constructor
public MyCustomView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
...
TypedArray a = context.getTheme().obtainStyledAttributes(
attrs,
R.styleable.MyCustomView,
defStyle, 0
);
try {
int headerLayout = a.getResourceId(R.styleable.MyCustomView_headerLayout, 0);
} finally {
a.recycle();
}
...
}
From here on you can inflate headerLayout with LayoutInflater
I try implement compound view for my dashboard activity. It's Button with TextView. Need for my theme.
I have attr.xml file
<declare-styleable name="DashboardButton">
<attr name="drawableTop" format="reference"/> <!-- i want set android:drawableTop of button-->
<attr name="btnText" format="string" /> <!-- text about button functionality-->
<attr name="tvText" format="string" /> <!-- additional information -->
</declare-styleable>
also have dashboard_button.xml layout
<?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" >
<Button
android:id="#+id/btn"
style="#style/DashboardButton"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true" />
<TextView
style="#style/btn_add_info"
android:id="#+id/txtView"
android:text="0"/>
</RelativeLayout>
also have custom component DashboardButton
public class DashboardButton extends RelativeLayout {
private TextView txtView;
private Button btn;
public DashboardButton(Context context) {
super(context);
}
public DashboardButton(Context context, AttributeSet attrs) {
super(context, attrs);
LayoutInflater inflater = LayoutInflater.from(context);
inflater.inflate(R.layout.dashboard_button, this);
loadViews(attrs);
}
public DashboardButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
LayoutInflater inflater = LayoutInflater.from(context);
inflater.inflate(R.layout.dashboard_button, this);
loadViews(attrs);
}
private void loadViews(AttributeSet attrs) {
txtView = (TextView) findViewById(R.id.txtView);
btn = (Button) findViewById(R.id.btn);
TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.DashboardButton);
txtView.setText(a.getString(R.styleable.DashboardButton_tvText));
btn.setText(a.getString(R.styleable.DashboardButton_btnText));
//i think issue here but can't understand what i should do
Drawable topDrawable = a.getDrawable(R.styleable.DashboardButton_drawableTop);
btn.setCompoundDrawables(null, topDrawable, null, null);
a.recycle();
}
public void setTxtViewText(CharSequence text) {
txtView.setText(text);
}
}
and finally i have
<my.package.name.DashboardButton
android:id="#+id/Btn"
style="#style/DashboardButton"
app:btnText="#string/my_function"
app:tvText="#string/add_info"
app:drawableTop="#drawable/function_logo">
</my.package.name.DashboardButton>
All work fine, except app:drawableTop drawable not load at run time, I dont see drawable. Can you help me by advice?
You need to set the bounds for your drawable:
topDrawable.setBounds( new Rect( 0, 0, w, h ) );
or alternatively use:
btn.setCompoundDrawablesWithIntrinsicBounds(null, topDrawable, null, null);