As you can see I have an UpdatableView in xml file with updatable_view id, but I can't select it via findViewById. The id somehow gets removed and I don't know why. I printed out the view hierarchy and this particular view doesn't have an id. the others have of course!
what can be the problem? I've tried cleaning, rebuilding, regenerating R. nothing helps!
UPDATE
in my activity's onCreate I do this
setContentView(R.layout.starter_activity);
ButterKnife.bind(this);
in UpdatableView class that extends FrameLayout I do this:
public UpdatableView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
inflate(context,R.layout.torob_updatable_layout,this);
ButterKnife.bind(this);
}
and torob_updatable_layout.xml is as simple as this:
<?xml version="1.0" encoding="utf-8"?>
<merge
xmlns:android="http://schemas.android.com/apk/res/android">
<com.rey.material.widget.ProgressView
android:id="#+id/progress"
android:visibility="gone"
android:layout_width="48dp"
android:layout_height="48dp"
style="#style/CircleProgressBar"
android:layout_gravity="center"
/>
<com.rey.material.widget.Button
android:id="#+id/retry"
style="#style/Button"
android:text="تلاش دوباره"
android:layout_gravity="center"
android:visibility="gone"
/>
</merge>
You have to use like below.
UpdatableView updateView = (UpdatableView)findViewById(R.id.updatable_view);
After hours of perplexity I found that one of my UpdatableView constructors was like this:
public UpdatableView(Context context, AttributeSet attrs) {
this(context, null, 0);
}
instead it should've been like this:
public UpdatableView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
Jesus! Make sure to pass the attrs or you won't get an id with your view.
Related
I have a custom view that extends the constraint layout as follows :
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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="wrap_content">
<TextView
android:id="#+id/textViewMyTitle"
style="#style/LabelLowLevel"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="My Title"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="#+id/buttonEditMy"
style="#style/InlineButtonTransparent"
android:layout_width="wrap_content"
android:text="#string/edit"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/textViewMyTitle" />
<Button
android:id="#+id/buttonPlayMy"
style="#style/InlineButtonHot"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/play"
app:layout_constraintStart_toEndOf="#+id/buttonEditMy"
app:layout_constraintTop_toBottomOf="#+id/textViewMyTitle" />
</androidx.constraintlayout.widget.ConstraintLayout>
The view has some attributes :
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="MyCard">
<attr name="Mytitle" format="string"/>
<attr name="Mydescription" format="string"/>
<attr name="Myid" format="string"/>
</declare-styleable>
</resources>
And then the corresponding Java class :
public class MyCard extends ConstraintLayout {
public MyCard(#NonNull Context context) {
super(context);
}
public MyCard(#NonNull Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public MyCard(#NonNull Context context, #Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
public MyCard(#NonNull Context context, #Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context, attrs);
}
public String Description;
public String Topic;
public String MyId;
private void init(Context ctx, AttributeSet attrs) {
TypedArray CustomAttr = ctx.obtainStyledAttributes(attrs, R.styleable.MyCard);
Description = CustomAttr.getString(R.styleable.MyCard_Mydescription);
Topic = CustomAttr.getString(R.styleable.MyCard_Mytitle);
MyId = CustomAttr.getString(R.styleable.MyCard_Myid);
LayoutInflater inflater = (LayoutInflater)ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.Mycard, this, true); // <<<<<< the error is raised here
CustomAttr.recycle();
}
}
When running the code, I'm getting the error :
java.lang.RuntimeException:
Unable to start activity ComponentInfo{com.colman.myapp/com.colman.myapp.Activity20_PersonalSpace}:
android.view.InflateException: Binary XML file line #49 in com.colman.myapp:layout/activity_activity20_personal_space:
Binary XML file line #49 in com.colman.myapp:layout/activity_activity20_personal_space:
Error inflating class com.colman.myapp.Libraries.views.MyCard
Does anyone know how to solve that please ?
Tthanks.
Cheers
Try to change the way you inflate the layout:
private void init(Context ctx, AttributeSet attrs) {
inflate(ctx, R.layout.Mycard, this);
TypedArray CustomAttr = ctx.obtainStyledAttributes(attrs, R.styleable.MyCard);
Description = CustomAttr.getString(R.styleable.MyCard_Mydescription);
Topic = CustomAttr.getString(R.styleable.MyCard_Mytitle);
MyId = CustomAttr.getString(R.styleable.MyCard_Myid);
CustomAttr.recycle();
}
try to change
inflater.inflate(R.layout.Mycard, this, true);
to
inflater.inflate(R.layout.Mycard, this, false);
I am working in android project about preferences. I want to take Integer value in EditTextPreference. I search with this subject and I can use with this java class.
import androidx.preference.EditTextPreference;
public class IntegerEditTextPreference extends EditTextPreference {
public IntegerEditTextPreference(Context context) {
super(context);
}
public IntegerEditTextPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
public IntegerEditTextPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected String getPersistedString(String defaultReturnValue) {
int defaultValue = -1;
try {
defaultValue = Integer.valueOf(defaultReturnValue);
} catch(NumberFormatException e) {
}
return String.valueOf(getPersistedInt(defaultValue));
}
#Override
protected boolean persistString(String value) {
return persistInt(Integer.valueOf(value));
}
}
But, I can't use in XML. When I use;
<com.example.A.IntegerEditTextPreference
android:defaultValue="80"
android:inputType="numberPassword"
android:key="Speed"
android:persistent="false"
android:numeric="integer"
android:maxLength="3"
android:title="Choose Speed" />
I take this error: "Element is Not Allowed Here". Now, I am searcing and they say I must use xml folder in drawable but it is Preference XML so I can't it. What can I do?
Edit: I add my xml file.
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<PreferenceCategory android:title="Notification">
<SwitchPreference
android:defaultValue="false"
android:icon="#drawable/B"
android:key="B"
android:title="B" />
<SwitchPreference
android:defaultValue="false"
android:icon="#drawable/A"
android:key="A"
android:title="A" />
<com.example.A.IntegerEditTextPreference
android:defaultValue="80"
android:inputType="numberPassword"
android:key="Speed"
android:persistent="false"
android:numeric="integer"
android:maxLength="3"
android:title="Choose Speed" />
</PreferenceCategory>
</PreferenceScreen>
You can constraint on EditTextPreference. But, When you get this value, converting Integer or other values.
<EditTextPreference
android:key="Speed"
android:selectAllOnFocus="true"
android:singleLine="true"
android:summary="A"
android:title="A" />
What I want to achieve:
A java Activity with a belonging xml-layout, where the user can enter the names of all players. Here is how it looks like:
If you click the plus-button you can enter another player (Spieler is german for player). It should be a wrapped view until the maximum height is reached.
I found a very similar question here:
How to set a maximum height with wrap content in android?
There is code given with the comment: "you can add this to any view (override onMeasure in a class inherited from a view)"
Here my question: My belonging java-file to the xml-layout inherits from Activiy thus doesnt know the super.onMeasure() method. Do you have any tipps what I can do? Can I have an Activity-java-file and a View-java-file to one layout? Thanks a lot!
You have to create a custom view that extends ScrollView and then use that view in your xml
public class ScrollViewWithMaxHeight extends ScrollView {
public static int WITHOUT_MAX_HEIGHT_VALUE = -1;
private int maxHeight = WITHOUT_MAX_HEIGHT_VALUE;
public ScrollViewWithMaxHeight(Context context) {
super(context);
init(context, null, 0, 0);
}
public ScrollViewWithMaxHeight(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs, 0, 0);
}
public ScrollViewWithMaxHeight(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context, attrs, defStyle, 0);
}
private void init(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes){
TypedArray a = context.getTheme().obtainStyledAttributes(
attrs, R.styleable.custom_ScrollViewWithMaxHeight, defStyleAttr, defStyleRes);
maxHeight =
a.getDimensionPixelSize(R.styleable.max_height,maxHeight);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
try {
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
if (maxHeight != WITHOUT_MAX_HEIGHT_VALUE
&& heightSize > maxHeight) {
heightSize = maxHeight;
}
heightMeasureSpec = MeasureSpec.makeMeasureSpec(heightSize, MeasureSpec.AT_MOST);
getLayoutParams().height = heightSize;
} catch (Exception e) {
LogManager.error(this, "onMesure", "Error forcing height", e);
} finally {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
public void setMaxHeight(int maxHeight) {
this.maxHeight = maxHeight;
}
}
You also have to create an attrs.xml file in your values folder and add this to it.
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools">
<declare-styleable name="custom_ScrollViewWithMaxHeight">
<attr name="max_height" format="dimension" />
</declare-styleable>
</resources>
You can then reference the view like this
<the.package.where.the.view.is.ScrollViewWithMaxHeight
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:max_height="150dp">
</the.package.where.the.view.is.ScrollViewWithMaxHeight>
Its a so simple.
instead of use ScrollView, I prefer you have to use the RecycleView, Adapter and for plus icon use Fab button.
Without creating the custom view and all, you can achieve the maximum hight of RecycleView and bottom with Fab button by using theandroid:layout_height="wrap_content" in your .xml file as
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
tools:context="com.tejadroid.testing.MainActivity"
tools:showIn="#layout/app_bar_main">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.RecyclerView
android:id="#+id/rv_item"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipToPadding="false"
android:paddingBottom="56dp" />
<android.support.design.widget.FloatingActionButton
android:id="#+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right|bottom"
android:layout_margin="#dimen/fab_margin"
app:srcCompat="#android:drawable/ic_input_add" />
</FrameLayout>
</RelativeLayout>
I've created a layout for a button format I use multiple times. The button format has a TextView and an ImageView. With the way I'm including this layout in my main activity, I don't think I'm able to change the text of the inner TextView dynamically in Java or in the XML. Is there a different way I can do this such that I can set the text of the inner TextView?
Layout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal" android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/settingslayout">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="25dp"
android:layout_marginTop="13dp"
android:textSize="20dp"
android:text="CHANGE ME"
android:id="#+id/text" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:layout_marginRight="25dp"
android:layout_alignParentRight="true"
android:src="#drawable/left"
android:adjustViewBounds="true"
android:scaleType="centerCrop"
android:maxHeight="30dp"
android:maxWidth="30dp"/>
</RelativeLayout>
Main Activity:
...
<include layout="#layout/settings_layout"
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:layout_below="#+id/accountStaticUnderline"
android:id="#+id/termBegin"
android:text="TEST" /> //DOESNT WORK
...
</RelativeLayout>
Setting the text that way won't work because android:text is not applicable to the <include> tag. More specifically, it's not applicable to the thing being included, which is a RelativeLayout. (You couldn't put the android:text on the RelativeLayout and have it apply to the TextView, nor would you expect that to work.)
My first suggestion (and the easiest immediate solution) is to use TextView's built in support for compound drawables so you can simply use TextViews instead of includes and have a style resource for the attributes you want.
If that's not good enough for your use case, then you might need to make a custom View. This view will replace the RelativeLayout and have the TextView and ImageView as children. The main thing to decide is where and how the children are created and their references are obtained: you can create them manually in Java when the parent is being constructed; or you can use some combination of layouts with <include>s and/or <merge>s. Making the text attribute work then requires some use of a <declare-styleable>.
I assume you want the children to always appear the same and that you want to reuse the layout you already made (i.e. you don't want to set all the attributes manually), so this is what I would probably do:
public class MyButton extends RelativeLayout {
private TextView mTextView;
private ImageView mImageView;
public MyButton(Context context) {
super(context);
init(context, null);
}
public MyButton(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public MyButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
public MyButton(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context, attrs);
}
private void init(Context context, AttributeSet attributeSet) {
LayoutInflater inflater = LayoutInflater.from(context);
inflater.inflate(R.layout.my_button, this, true); // used with merge tag
mTextView = (TextView) findViewById(R.id.text);
mImageView = (ImageView) findViewById(R.id.image);
int[] attrs = {android.R.attr.text};
TypedArray a = context.obtainStyleAttributes(attributeSet, attrs);
String text = a.getString(0, null);
mTextView.setText(text);
a.recycle();
}
}
In res/layout/my_button.xml:
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="25dp"
android:layout_marginTop="13dp"
android:textSize="20dp"
android:text="CHANGE ME"
android:id="#+id/text" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:layout_marginRight="25dp"
android:layout_alignParentRight="true"
android:src="#drawable/left"
android:adjustViewBounds="true"
android:scaleType="centerCrop"
android:maxHeight="30dp"
android:maxWidth="30dp"/>
</merge>
In your activity layout:
...
<!-- no more include -->
<com.package.MyButton
android:id="#+id/something"
android:layout_width="..."
android:layout_height="..."
android:text="..." />
<!-- you can have multiple instances with different IDs -->
<com.package.MyButton
android:id="#+id/something_else"
android:layout_width="..."
android:layout_height="..."
android:text="..." />
...
You could also use your own <declare-styleable> for the custom view, which will be necessary if later you want to have custom XML attributes for it, but the approach above should be sufficient.
sure, just type this code in your activity
((TextView)findViewById(R.id.text)).setText("enter_text_here");
I have encountered an issue i am trying to resolve (or understand better the way it should be done) in creation of custom Layout in Android.
I want to create a custom RelativeLayout class for my use, which is defined in a layout XML file.
my_relative_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<com.mypackage.MyRelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:id="#+id/image_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#null"
android:scaleType="fitStart"
android:src="#drawable/my_drawable"/>
<TextView
android:id="#+id/text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#color/title_gray"
android:layout_below="#id/image_view"
android:gravity="center"
android:text="#string/placeholder" />
</com.mypackage.MyRelativeLayout>
Usage
public class MyRelativeLayout extends RelativeLayout {
private AttributeSet attrs;
private ImageView imageView;
private TextView textView;
public MyRelativeLayout(Context context) {
super(context);
}
public MyRelativeLayout(Context context, AttributeSet attrs) {
super(context, attrs);
this.attrs = attrs;
}
public MyRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.attrs = attrs;
}
#Override
protected void onFinishInflate() {
super.onFinishInflate();
if (attrs != null) {
TypedArray a = getContext().getTheme().obtainStyledAttributes(attrs, R.styleable.MyRelativeLayout, 0, 0);
drawableResource = a.getResourceId(R.styleable.MyRelativeLayout.image_view, 0);
a.recycle();
}
imageView = (ImageView) findViewById(R.id.image_view);
textView = (TextView) findViewById(R.id.text_view);
if (drawableResource != 0 && imageView != null) {
imageView.setImageResource(drawableResource);
}
}
}
My issue is that i want to initialise this layout both in another XML and in code.
But as I wrote my class and XML, i can only use it in code by doing:
myLayout = (MyRelativeLayout) LayoutInflater.from(this.getActivity()).inflate(R.layout.my_relative_layout, container, false);
When writing the following in another XML causes the onFinishInflate to fail on getViewById (returns null) and the childrenCount is 0
<com.mypackage.MyRelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_below="#id/another_layout"
app:image_view="#drawable/my_image" />
and doing the following, won't let me configure the custom image_view attribute.
<include layout="#layout/my_relative_layout"/>
To fix that, i can change the custom layout XML root element to be of type RelativeLayout and add the following to the beginning of onFinishInflate method:
LayoutInflater.from(getContext()).inflate(R.layout.my_relative_layout, this, true);
But the XML won't reference my class.
My questions are,
1. Am i missing something in the definition of the custom layout?
2. What is the correct definition for custom layout?
Thank you in advance!
First you should use the styled attributes in the contractor as shown in this example.
How can you expect from MyRelativeLayout that defined as fallow:
<com.mypackage.MyRelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_below="#id/another_layout"
app:image_view="#drawable/my_image" />
To be aware of views that are defined in my_relative_layout.xml?
To make it work you should create a costume layout and add it to com.mypackage.MyRelativeLayout manually.
Some thing like that:
costume_layout.xml
<?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">
<ImageView
android:id="#+id/image_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#null"
android:scaleType="fitStart"
android:src="#drawable/my_drawable"/>
<TextView
android:id="#+id/text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#color/title_gray"
android:layout_below="#id/image_view"
android:gravity="center"
android:text="#string/placeholder" />
</RelativeLayout>
Your costume view
public class MyRelativeLayout extends RelativeLayout {
private AttributeSet attrs;
private ImageView imageView;
private TextView textView;
public MyRelativeLayout(Context context) {
super(context);
init();
}
public MyRelativeLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public MyRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init(Context context){
LayoutInflater.from(context).inflate(R.layout.costume_layout, this);
}
}