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" />
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);
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>
So, I created a CustomView called ButtonWithCaption.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"
android:layout_weight="1"
android:background="?attr/selectableItemBackground"
android:paddingBottom="#dimen/spacing_normal"
android:paddingLeft="#dimen/spacing_small"
android:paddingRight="#dimen/spacing_small"
android:paddingTop="#dimen/spacing_normal">
<ImageView
android:id="#+id/bwc_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginBottom="2dp"
android:scaleType="centerCrop" />
<TextView
android:id="#+id/bwc_caption"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#id/bwc_icon"
android:textAlignment="center" />
Along with its controller ButtonWithCaption.java
public class ButtonWithCaption extends RelativeLayout {
private ImageView mImageView;
private TextView mTextView;
private int mIconSrc;
private String mCaptionText;
private boolean mShowIcon;
private boolean mShowText;
public ButtonWithCaption(Context context) {
super(context);
init(context, null, 0);
}
public ButtonWithCaption(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs, 0);
}
public ButtonWithCaption(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs, defStyleAttr);
}
private void init(Context context, AttributeSet attrs, int defStyleAttr) {
TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.ButtonWithCaption, 0, 0);
try {
mIconSrc = a.getResourceId(R.styleable.ButtonWithCaption_iconSrc, 0);
mCaptionText = a.getString(R.styleable.ButtonWithCaption_captionText);
mShowIcon = a.getBoolean(R.styleable.ButtonWithCaption_showIcon, mIconSrc != 0);
mShowText = a.getBoolean(R.styleable.ButtonWithCaption_showText, !mCaptionText.isEmpty());
mImageView = (ImageView) findViewById(R.id.bwc_icon);
mTextView = (TextView) findViewById(R.id.bwc_caption);
mImageView.setImageResource(mIconSrc);
mTextView.setText(mCaptionText);
} finally {
a.recycle();
}
}
}
Nothing fancy.
And then, I declare custom attributes in attrs.xml
<resources>
<declare-styleable name="ButtonWithCaption">
<attr name="iconSrc" format="reference" />
<attr name="captionText" format="string" />
<attr name="showIcon" format="boolean" />
<attr name="showText" format="boolean" />
</declare-styleable>
</resources>
And this is my activity_main.xml
<?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"
tools:context="id.foodmap.foodmapcustomviews.MainActivity">
<id.foodmap.foodmapcustomviews.ButtonWithCaption
android:id="#+id/button_with_caption"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:captionText="Test"
app:iconSrc="#drawable/ic_email_gray_24dp" />
</RelativeLayout>
...but weirdly, Android Studio's preview gave me render error :
Failed to instantiate one or more classes
with stacktrace :
java.lang.NullPointerException
at id.foodmap.foodmapcustomviews.ButtonWithCaption.init(ButtonWithCaption.java:54)
at id.foodmap.foodmapcustomviews.ButtonWithCaption.(ButtonWithCaption.java:29)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at org.jetbrains.android.uipreview.ViewLoader.createNewInstance(ViewLoader.java:475)
at org.jetbrains.android.uipreview.ViewLoader.loadClass(ViewLoader.java:262)
at org.jetbrains.android.uipreview.ViewLoader.loadView(ViewLoader.java:220)
at com.android.tools.idea.rendering.LayoutlibCallbackImpl.loadView(LayoutlibCallbackImpl.java:186)
at android.view.BridgeInflater.loadCustomView(BridgeInflater.java:334)
at android.view.BridgeInflater.loadCustomView(BridgeInflater.java:345)
at android.view.BridgeInflater.createViewFromTag(BridgeInflater.java:245)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:727)
at android.view.LayoutInflater.rInflate_Original(LayoutInflater.java:858)
at android.view.LayoutInflater_Delegate.rInflate(LayoutInflater_Delegate.java:70)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:834)
at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:821)
at android.view.LayoutInflater.inflate(LayoutInflater.java:518)
at android.view.LayoutInflater.inflate(LayoutInflater.java:397)
at com.android.layoutlib.bridge.impl.RenderSessionImpl.inflate(RenderSessionImpl.java:324)
at com.android.layoutlib.bridge.Bridge.createSession(Bridge.java:429)
at com.android.ide.common.rendering.LayoutLibrary.createSession(LayoutLibrary.java:368)
at com.android.tools.idea.rendering.RenderTask$2.compute(RenderTask.java:567)
at com.android.tools.idea.rendering.RenderTask$2.compute(RenderTask.java:549)
at com.intellij.openapi.application.impl.ApplicationImpl.runReadAction(ApplicationImpl.java:863)
at com.android.tools.idea.rendering.RenderTask.createRenderSession(RenderTask.java:549)
at com.android.tools.idea.rendering.RenderTask.lambda$inflate$1(RenderTask.java:680)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
My findViewById() from ButtonWithCaption.java to find TextView and ImageView also returns null.
Anyone know what caused this? Because it doesn't even show up in the editor preview window.
P.S. If I use , The preview show the element correctly.
P.S.S. It compiled to my phone with no error, but no ButtonWithCaption shown.
Thanks in advance
You are getting a NullPointerException because you have not inflated the views from ButtonWithCaption.xml. One way to fix this is with the static View.inflate() method:
private void init(Context context, AttributeSet attrs, int defStyleAttr) {
TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.ButtonWithCaption, 0, 0);
try {
mIconSrc = a.getResourceId(R.styleable.ButtonWithCaption_iconSrc, 0);
mCaptionText = a.getString(R.styleable.ButtonWithCaption_captionText);
mShowIcon = a.getBoolean(R.styleable.ButtonWithCaption_showIcon, mIconSrc != 0);
mShowText = a.getBoolean(R.styleable.ButtonWithCaption_showText, !mCaptionText.isEmpty());
View v = View.inflate(context, R.layout.ButtonWithCaption, this); // add this line
mImageView = (ImageView) findViewById(R.id.bwc_icon);
mTextView = (TextView) findViewById(R.id.bwc_caption);
mImageView.setImageResource(mIconSrc);
mTextView.setText(mCaptionText);
} finally {
a.recycle();
}
}
You have to replace the tag <RelativeLayout> with your class, something like this:
<?xml version="1.0" encoding="utf-8"?>
<com.yourpackage.app.ButtonWithCaption xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
...
>
...
</com.yourpackage.app.ButtonWithCaption>
com.yourpackage.app should be the path where your ButtonWithCaptionclass is.
EDIT:
AYour posted layout sould be your activity layout, the ButtonWithCaptionclass should be your xml element, not your xml name, so change the name, replace the RelativeLayout with your custom class and try it.
I want to implement custom functions to download image from ImageView like this app:imageUrl="#{status.imageUrl}" in the below code:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="status"
type="com.databinding.data.Status" />
</data>
<RelativeLayout
android:id="#+id/status_container"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="#+id/status_avatar"
android:layout_width="64dp"
android:layout_height="64dp"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:contentDescription="#null"
app:imageUrl="#{status.imageUrl}"/>
</RelativeLayout>
</layout>
How to write this function which can download image automate from a #{status.imageUrl} ?
Use this library com.android.databinding.
For this work, you need to a lib like android databinding lib.
In this library, first add below scripts to build.gradle of project:
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.5.0'
classpath 'com.android.databinding:dataBinder:1.0-rc4'
}
}
And add this codes to top the build.gradle of module file:
apply plugin: 'com.android.databinding'
And create your class for example: class BindingCustom and write this codes:
public class BindingCustom {
#BindingAdapter({"imageUrl"})
public static void loadImage(final ImageView view, String url) {
Picasso.with(view.getContext()).load(url).into(view);
}
}
In the BindingCustom class you have loadImage method to download image from URL by your interested way, but I use the Picasso library because it's a common lib for this job and you can change it to your codes.
This is a helpful link for more information
below is what i prefer:
first make a custom class extended form image view
import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.util.AttributeSet;
import android.widget.ImageView;
public class MyImageView extends ImageView {
public MyImageView(Context context) {
super(context);
downloader(null);
}
public MyImageView(Context context, AttributeSet attrs) {
super(context, attrs);
downloader(attrs);
}
public MyImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
downloader(attrs);
}
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
public MyImageView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
downloader(attrs);
}
private void downloder(AttributeSet attr){
// TAKE THE LINK AND DOWNLOAD IMAGE HERE
}
}
second declare a styleable in your res folder
<declare-styleable name="MyImageView">
<attr name="imageUrl" format="string"/>
</declare-styleable>
at last lets make our downloader function
private void downloader(AttributeSet attrs) {
if (attrs!=null) {
TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.MyImageView);
String url = a.getString(R.styleable.MyImageView_imageUrl);
// First check whether we have such a property then
// DOWNLOAD IT WITH ANY LIBRARY YOU LIKE
// in this case i used IMAGE LOADER
if(url!=null)
ImageLoader.getInstance().displayImage(url,this);
}
}
now you can easily add the link in your xml
<com.raianraika.example.MyImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:imageUrl="www.google.com"/>
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.