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>
Related
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.
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");
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.
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 know there are dozens similar post, but it looks to me everything is correct here:
The custom widget:
public class DoubleTextItem extends LinearLayout {
private TextView txtMain;
private TextView txtDescription;
public DoubleTextItem(Context context) {
super(context);
}
public DoubleTextItem(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
protected void onFinishInflate() {
super.onFinishInflate();
((Activity)getContext()).getLayoutInflater().inflate(R.layout.widget_double_text_item, this);
setupViewItems();
}
private void setupViewItems() {
txtMain = (TextView) findViewById(R.id.txtMain);
txtDescription = (TextView) findViewById(R.id.txtDecription);
}
public void setDescription(String text) {
txtDescription.setText(text);
}
}
The custom widget layout xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:id="#+id/txtMain"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/txtDecription"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
ANd here inside an activity function i get a casting error,
LayoutInflater inflater = LayoutInflater.from(this);
DoubleTextItem item = (DoubleTextItem) inflater.inflate(R.layout.widget_double_text_item, layout);
item.setText(som-txt);
item.setDescription("#"+athlete.getString("position"));
Here, the root View is a LinearLayout but you try to cast it your custom class:
DoubleTextItem item = (DoubleTextItem) inflater.inflate(R.layout.widget_double_text_item, layout);
The standard advice is:
All DoubleTextItems are LinearLayouts, but not all LinearLayouts are DoubleTextItems.
Meaning you cannot downcast objects from a LinearLayout to a DoubleTextItem, there are too many assumptions and Java won't let you do it.
If you want a DoubleTextItem in your layout you need to use:
<your.package.name.DoubleTextItem
... />
(Also, calling inflate inside onFinishInflate() seems a little silly especially since you don't save the inflated item... If you want to inflate a different layout, don't inflate the first one.)
Overall it looks like you are trying to recreate the now deprecated TwoLineListItem, perhaps you can learn some pointers from it's source code (or just use the TwoLineListItem.)