TextSwitcher - Get the style attribute and pass it to another view - android

I am using a TextSwitcher with a TextView factory. I would like to pass the style I set on the TextSwitcher down to the TextViews.
TextSwitcher does not have a 3 arg constructor.
Is it possible to get the style attribute from the attribute set?
Xml
<com.my.TextSwitcher
style="#style/My.TextView.Style"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
Java
public class MyTextSwitcher extends TextSwitcher {
public MyTextSwitcher(Context context, AttributeSet attrs) {
super(context, attrs);
int style = attrs.getAttributeIntValue("", "style", 0); // I tried this to no avail
setFactory(new MyTextViewFactory(context, attrs, style));
}
private static class MyTextViewFactory implements ViewFactory {
private final Context context;
private final AttributeSet attrs;
private final int style;
public MyTextViewFactory(Context context, AttributeSet attrs, int style) {
this.context = context;
this.attrs = attrs;
this.style = style;
}
#Override
public View makeView() {
return new TextView(context, attrs, style);
}
}
}
is the only answer to make my own custom attribute of int that will pass the style? I can't use the built in style tag?

You can retrieve the style attribute(and pass it to the inner views) using:
attrs.getStyleAttribute()
or its equivalent(as the docs mention):
getAttributeResourceValue(null, "style")

One alternative is to declare the TextView's in XML, however this gives less flexibility to the amount of child TextView's I can have.
<com.my.TextSwitcher
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="#style/My.TextView.Style"
android:text="#string/some_text" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="#style/My.TextView.Style"
android:text="#string/some_other_text" />
</com.my.TextSwitcher>

Related

Android custom attributes with data binding

I have a big library of custom components that I want to use in my Android app.
All components use custom attributes to customize its content.
This is a sample component declared in a XML file:
<myapp.CustomTextView
android:id="#+id/text_view_1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="25dp"
android:layout_marginRight="25dp"
android:layout_marginBottom="8dp"
custom:textContent="This is my text" />
This is the custom attributed declared:
<declare-styleable name="CustomTextView">
<attr name="textContent" format="string" />
</declare-styleable>
And this is the implementation of the custom component:
public class CustomTextView extends TextView {
private Context context;
public CustomTextView(Context context) {
this(context, null);
}
public CustomTextView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CustomTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
readAttrs(context, attrs);
}
private void readAttrs(Context context, AttributeSet attrs) {
TypedArray array = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CustomTextView,0, 0);
try {
String content = array.getString(R.styleable.CustomTextView_textContent);
initContent(context, content);
} finally {
array.recycle();
}
}
private void initContent(Context context, String content) {
...
}
}
The problem is that I'm using data binding in my app, so if I do this, the app doesn't compile:
<myapp.CustomTextView
android:id="#+id/text_view_1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="25dp"
android:layout_marginRight="25dp"
android:layout_marginBottom="8dp"
custom:textContent="#{mainView.content}" />
After reading a lot, the solution seems to be to create a bindingadapter for that custom attribute, but in my case, create a binding adapter for every custom attribute would be a huge work because there are tons of components and attributes.
Is there a way to reduce this amount of work or to adapt data binding to these custom attributes?

Android: How to initialise a custom View in code and connect it to an existing xml view

I have my own custom view class like below:
public class speak extends ConstraintLayout implements View.OnClickListener {
private TextView text;
private ImageView img;
public speak(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.getTheme().obtainStyledAttributes(
attrs,
R.styleable.speak,
0, 0);
try {
text = findViewById(a.getResourceId(R.styleable.speak_text,0));
img = findViewById(a.getResourceId(R.styleable.speak_img, 0));
} finally {
a.recycle();
}
}
}
With this I created attr.xml where I put this resource:
<declare-styleable name="speak">
<attr name="text" format="string"/>
<attr name="img" format="reference"/>
</declare-styleable>
and I also created my own layout xml of how the custom view should look. This way I can add multiple views easily in activity_main.xml. I started by adding one view in activity_main.xml. But now I want to link it to the custom view class in onCreate. what I am doing is this:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
speak sl = findViewById(R.id.ss);
sl.seImage(getResources().getIdentifier("com.example.app:drawable/img.png", null, null));
}
where setImage is my own setter for the components in the customView. However, this is returning a null pointer exception which I think I understand since I am not creating a new speak Object and passing attributes in the constructor and so on.
create a new view object but at the same time pass it the xml element which sets its position on screen apart form other stuff.
I am also not sure what should I pass to AttributeSet in the constructor.
udpate
this is the error:
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.ImageView.setImageResource(int)' on a null object reference
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2913)
This is because my setter contains img.SetImageResource(int) to get a drawable Id and set te image to that image in drawable folder
Please check GoEditText I have used:
public class GoEditText extends FrameLayout {
private TextInputLayout inputLayout;
private AppCompatEditText editText;
public GoEditText(Context context) {
super(context);
init(context, null);
}
public GoEditText(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
this.context = context;
LayoutInflater.from(context).inflate(R.layout.go_edit_text, this, true);
inputLayout = findViewById(R.id.inputLayout);
editText = findViewById(R.id.editText);
if (attrs != null) {
TypedArray typedArray = context.obtainStyledAttributes(attrs,
R.styleable.GoEditText, -1, 0);
int edtType = typedArray.getInt(R.styleable.GoEditText_edtTextType, 0);
boolean isEditable = typedArray.getBoolean(
R.styleable.GoEditText_isEditAble, true);
}
}
Below is xml go_edit_text.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.TextInputLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/inputLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:passwordToggleDrawable="#null">
<android.support.v7.widget.AppCompatEditText
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
style="#style/CJEditText"
android:id="#+id/editText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawablePadding="5dp"
app:backgroundTint="#color/gray_3" />
</android.support.design.widget.TextInputLayout>
Now you can use it directly in acitivity.xml as
<com.package.name.component.GoEditText
android:id="#+id/myid"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:edtTextType="selection"
app:errorMsg="#string/error_employee_type"
app:hint="#string/hint_employee_type" />
Now in onCreate
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
GoEditText edt= findViewById(R.id.myId);
edt.editText.setText("hello");
}
Or you can create a getter method in CustomView for say edittext( imageView in your case)

Add hint text to programatically added TextInputLayout

Hi I have created custom component for TextInputLayout. I want to set hint text to TextInputLayout. I am adding custom class which extends TextInputLayout into my root layout. I tried it in following way:
<android.support.design.widget.TextInputLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColorHint="#color/gray"
android:theme="#style/editTextSelectedTheme"
android:layout_marginTop="#dimen/margin_10"
>
<EditText
android:id="#+id/form_et"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
public class FormEditText extends TextInputLayout
{
TextInputLayout view;
public FormEditText(Context context) {
super(context);
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = (TextInputLayout)inflater.inflate(R.layout.form_edit_text, this, true);
initUI();
}
public FormEditText(Context context, AttributeSet attrs) {
super(context, attrs);
}
public FormEditText(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
}
And finally in my fragment:
FormEditText gadgetName = new FormEditText(getContext());
gadgetName.setHint(getResources().getString(R.string.gadget_name_hint));
formContainer.addView(gadgetName);
Above code adds new TextInputLayout in my view but not adding hint text for it. Am I doing anything wrong? Need Some help. Thank you.
I did few changes as per comment below.
public class FormEditText extends LinearLayout
view = inflater.inflate(R.layout.form_edit_text, this, true);
Now it si showing hint text as per required.But now it is not showing my edit text value.It is not taking any input value.

Android: best way to control view that added dynamically?

As the title, i want to know if there is a the best way to control a view that added dynamically. (we have to keep reference to the view that was added)
Some time, for a complex request we have to add view in runtime. The is some ways to do that. In my case:
Some time i use a listview/recyclerview and control view via the list/recycleview adapter.
Other way is use a hashmap.
Do you have any other ideas? and how it work?
I prefer way, when I define View both by Java and XML file. View created like this, gives you ability to call your own Java methods, but you don`t need to create whole layout dynamically in Java. Little example:
MyView.java:
public class MyView extends LinearLayout {
TextView textView;
public MyView(Context context) {
super(context);
init();
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public MyView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
public void init() {
inflate(getContext(), R.layout.my_view, this);
setOrientation(VERTICAL);
textView = (TextView) findViewById(R.id.text_view);
}
public MyView setContent(String value) {
textView.setText(value);
return this;
}
}
my_view.xml:
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<TextView
android:id="#+id/text_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</merge>
After that, you can simply add it in you layout through Java:
cont.addView(new MyView(this).setContent("Value"));
or xml:
<com.path.to.your.view.MyView
android:id="#+id/my_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>

how to set Android Typeface from xml

Typeface fontRobo = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-Black.ttf");
viewTotalValue.setText(total.toString());
You could create your own TextView by overriding the TextView like this:
public class MyTextView extends TextView {
public MyTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setType(context);
}
public MyTextView(Context context, AttributeSet attrs) {
super(context, attrs);
setType(context);
}
public MyTextView(Context context) {
super(context);
setType(context);
}
private void setType(Context context){
this.setTypeface(Typeface.createFromAsset(context.getAssets(),
"foo.ttf"));
this.setShadowLayer(1.5f, 5, 5, getContext().getResources().getColor(R.color.black_shadow));
}
}
And use it like this:
<com.your.project.package.MyTextView
android:id="#+id/oppinfo_mtv_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:text="Player 1"
/>
You could create a custom class that extends TextView, let's say FontTextView.
Define a special string attribute for that class, let's say "font".
Then, in your FontTextView constructor based on the value of the font attribute, choose the appropriate Typeface from your assets.
See:
Creating a View Class Google Tutorial
Defining custom attributes SO Post
Extending TextView just for setting font looks so expensive and not good.
The most clear way is to use Android Data-Binding Framework and BindingAdapter:
#BindingAdapter("bind:font")
public static void setTypeface(TextView textView, int index) {
Typeface myTypeface = //retrieve typeface from cache, based on some font index
textView.setTypeface(myTypeface);
}
declaration in xml:
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:font="#{R.attr.Proxima_Nova_Regular}"
/>
attrs.xml:
<attr name="Proxima_Nova_Regular"/>
<attr name="Proxima_Nova_Black"/>
<attr name="Proxima_Nova_Bold"/>
or use resources integers same way
In your cache/creator helper determine dependencies between R.attr.Your Font and instance of typeface.

Categories

Resources