I'm trying to set "2 backgrounds" to a button, the first one is an xml file to make the button corners rounded and the second one is the png image that I want.
I tried to use android:background for my xml file and android:drawableTop for my image it's working but my image is not scalled in the button.
I know that we can use an imagebutton with android:scaleType="centerInside" to scale the picture but in my case I want to do it for a button because I need to put text in it ...
Can you help me with that ?
my xml file (for the rounded shape) :
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle">
<solid android:color="#FF008AB8"/>
<stroke android:color="#0299D0"/>
<corners android:radius="15dp"/>
</shape>
</item>
android:radius = "150dp"</selector>
Thanks
LooKuM
You can use a layerlist in xml drawable such that you set both the xml background and image as you exactly need then you set the background just once.
Here is an example
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle">
<corners android:radius="#dimen/quarter_margin" />
<stroke
android:width="1dp"
android:color="#color/ash_gray" />
<solid android:color="#color/white" />
</shape>
</item>
<item android:drawable="#drawable/blue_back">
</item>
</layer-list>
Another Solution:
To be able to use just one layout and control the image, You can make you own custom control, here is an example
public class RecordButton extends LinearLayout {
#BindView(R.id.record_switch)
SwitchCompat recordSwitch;
#BindView(R.id.record_toggle_button)
ToggleButton recordButton;
private boolean checkable = true;
public RecordButton(Context context) {
super(context);
init(context, null);
}
public RecordButton(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public RecordButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
private void init(#NonNull Context context, #Nullable AttributeSet attrs) {
LayoutInflater inflater = LayoutInflater.from(context);
inflater.inflate(R.layout.record_button, this);
ButterKnife.bind(this);
setGravity(Gravity.CENTER_HORIZONTAL);
applyAttr(attrs);
setChecked(false);
}
private void applyAttr(#Nullable AttributeSet attrs) {
if (attrs != null) {
TypedArray a = getContext().getTheme().obtainStyledAttributes(attrs,
R.styleable.RecordButton, 0, 0);
// Set Image
int drawableResource = a.getResourceId(R.styleable.RecordButton_drawable, -1);
if (drawableResource > -1) {
int color = a.getColor(R.styleable.RecordButton_tint, -1);
if (color > -1) {
Drawable drawable = ContextCompat.getDrawable(getContext(), drawableResource);
Drawable wrapDrawable = DrawableCompat.wrap(drawable);
DrawableCompat.setTint(wrapDrawable, Color.RED);
recordSwitch.setBackground(wrapDrawable);
} else {
recordSwitch.setBackgroundResource(drawableResource);
}
}
// Set Orientation
boolean isVertical = a.getBoolean(R.styleable.RecordButton_isVertical, false);
if (isVertical) {
setOrientation(VERTICAL);
}
a.recycle();
}
}
}
Here I inflated a layout and added to this class which inherits from LinearLayout
Here is the layout inflated
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<android.support.v7.widget.SwitchCompat
android:id="#+id/record_switch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="false"
android:thumb="#android:color/transparent" />
<ToggleButton
android:id="#+id/record_toggle_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#android:color/transparent"
android:clickable="false"
android:minHeight="0dp"
android:minWidth="0dp"
android:padding="#dimen/standard_margin"
android:textAllCaps="false"
android:textColor="#color/colorPrimary" />
</merge>
Now you main question comes, how can I change the image. In Java class you will find a method called applyAttr this method takes takes the custom attributes you added to your custom control
Here is an attr sample
this code to attrs.xml file
<declare-styleable name="RecordButton">
<attr name="drawable" format="reference" />
</declare-styleable>
I don't know if this works(and I can't add a comment lol) but try to set the Image in the rounded Corners XML file.
Related
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" />
Background isn't displayed. If the button hasn't background, it displayed OK
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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="match_parent"
android:background="?attr/colorBackgroundFloating"
tools:context=".MainActivity"
tools:layout_editor_absoluteY="25dp">
<Button
android:id="#+id/button_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_weight="1"
android:background="#drawable/my_round_button"
android:onClick="onClick"
android:text="#string/button_1"
android:visibility="visible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
When app button hasn't background, button looks like ractangle
my_round_button
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="ring">
<solid android:color="#FFFFFF" />
</shape>
What's wrong?
Button should looks like ring
A picture is worth a thousand words
So in your case to create a ring shape:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:innerRadius="80dp"
android:shape="ring"
android:thickness="5dp"
android:useLevel="false">
<solid android:color="#FFF" />
<size
android:width="200dp"
android:height="200dp" />
</shape>
You can change innerRadius, thickness, size property based on your UI requirements.
problem is in your shape.
for example you can change your shape to:
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:innerRadius="15dp"
android:thickness="10dp"
android:useLevel="false"
android:shape="ring"
>
<solid android:color="#FFFFFF" />
</shape>
I would recommend you to create custom view, which render the view in form of Circle and as per width/height we pass from the layout. It's more dynamic.
I did like the answer suggested by Son Truong but that seems not more generic as we need to hard code the size width/height.
Step 1: Create a theme in style.xml
<declare-styleable name="CircleCompatTextView">
<attr name="cctv_stroke_width" format="dimension" />
<attr name="cctv_background_color" format="color" />
<attr name="cctv_border_color" format="color" />
</declare-styleable>
Step 2: Create a custom view.
public class CircleCompatTextView extends AppCompatTextView {
private final Paint paintCircle = new Paint();
private final Paint paintStroke = new Paint();
private final Resources resources;
private int strokeWidth;
private int bgColor;
private int borderColor;
private int cxCy;
public CircleCompatTextView(Context context, AttributeSet attrs) {
super(context, attrs);
resources = context.getResources();
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CircleCompatTextView);
strokeWidth = a.getDimensionPixelSize(R.styleable.CircleCompatTextView_cctv_stroke_width, 1);
bgColor = a.getColor(R.styleable.CircleCompatTextView_cctv_background_color, resources.getColor(android.R.color.transparent));
borderColor = a.getColor(R.styleable.CircleCompatTextView_cctv_border_color, resources.getColor(android.R.color.background_dark));
a.recycle();
init();
}
private void init() {
paintCircle.setColor(bgColor);
paintCircle.setFlags(Paint.ANTI_ALIAS_FLAG);
paintStroke.setColor(borderColor);
paintStroke.setStyle(Paint.Style.STROKE);
paintStroke.setStrokeWidth(strokeWidth);
paintStroke.setFlags(Paint.ANTI_ALIAS_FLAG);
}
#Override
public void draw(Canvas canvas) {
canvas.drawCircle(cxCy, cxCy, cxCy - strokeWidth / 2, paintStroke);
canvas.drawCircle(cxCy, cxCy, cxCy - strokeWidth / 2, paintCircle);
super.draw(canvas);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = getMeasuredWidth();
int height = getMeasuredHeight();
int size = ((height > width) ? height : width);
cxCy = size / 2;
setMeasuredDimension(size, size);
}
}
Step 3: Usage of custom view
<CircleCompatTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center|center_vertical"
android:padding="16dp"
android:textAlignment="center"
app:cctv_background_color="#android:color/transparent"
app:cctv_border_color="#android:color/background_dark"
app:cctv_stroke_width="2dp" />
Here is the output
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 draw a simple line on top of some text in a TextView. I have looked at various examples which seem to override the onDraw() function but my understanding is that onDraw() is called when something is drawn.
I would like a vertical line in my TextView and at this moment in time I dont really care where it is, once I have the line I am sure I will be able to manipulate it to the position I would like.
I have a TextViewWithLines class extending TextView where the code will go:
public class TextViewWithLines extends TextView {
public TextViewWithLines(Context context){
super(context);
}
public TextViewWithLines(Context context, AttributeSet attrs) {
super(context, attrs);
}
public TextViewWithLines(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
and I also have a fragment where I would like the drawing of the line to be done when I create the view.
public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState){
View v = inflater.inflate(R.layout.fragment_hello_moon, parent, false);
t1 = (TextViewWithLines)v.findViewById(R.id.display1);
.................
}
Any help would be appreciated
As you describe, you simply need to do your drawing in onDraw().
Here is a (working) example of someone that wants all text in the Textview underlined;
How can I have a row separating line in TextView
One possible solution (just a simple XML layout):
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/small_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<TextView
android:id="#+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:textStyle="bold"
android:textSize="#dimen/define_your_size"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
/>
<LinearLayout
android:id="#+id/text_separator"
android:layout_width="match_parent"
android:layout_height="1dp"
android:orientation="vertical"
android:background="#color/define_your_color"
android:layout_alignParentTop="true"/>
</RelativeLayout>
If you want to draw a shape around a TextView (like a rectangle), you can define a drawable background and set the colors you want:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="true">
<shape>
<stroke android:color="#FFCC00" android:width="3dp"></stroke>
<corners android:radius="5dp"/>
<solid android:color="#FAFFA8"/>
</shape>
</item>
<item android:state_enabled="false">
<shape>
<stroke android:color="#FFFFFF" android:width="2dp"></stroke>
<corners android:radius="5dp"/>
<solid android:color="#00FFFFFF"/>
</shape>
</item>
<item>
<shape>
<stroke android:color="#DADADA" android:width="2dp"></stroke>
<corners android:radius="5dp"/>
<solid android:color="#FFFFFF"/>
</shape>
</item>
</selector>
I want to design a custom view that looks like this:
I searched for a solution, and what I got was to extend an EditText and customize it. I looked into the notepad editor example from Android, which did not help me much since I want to split the EditText into at least 4 parts.
The upper one is where M and DEG is written, the right part is where the x10^012 is written, the left part contains the current operation, and the last part is the biggest one where the digits are on.
However, I want you to guide me to the right direction to do it properly and tell me what pre-built view I should use as a base class to design this custom view. Any help will be appreciated.
One possibility is to extend the RelativeLayout class and in the constructor inflate an xml layout:
<RelativeLayout>
<TextView /> // M DEG(or 2 `TextView`)
<ImageButton /> //ImageView for the operation
<TextView /> //the digits
<TextView /> //the extra digits 10^12
</RelativeLayout>
Custom RelativeLayout class:
public class CustomView1 extends RelativeLayout {
public CustomView1(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.lcd_layout, this, true);
TextView part1 = (TextView) findViewById(R.id.the_id);
//other stuff
}
public CustomView1(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CustomView1(Context context) {
this(context, null);
}
}
Why not just design that in your layout? Stack some LinearLayouts on top of each other?
edit example of border question:
put this in your res/drawable folder:
<?xml version="1.0" encoding="utf-8"?>
<selector
xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape>
<gradient
android:startColor="#color/c1"
android:endColor="#color/c2"
android:angle="270" />
<stroke
android:width="1dp"
android:color="#color/stroke_color" />
</shape>
</item>
</selector>