I'm trying to create a parallelogram-shaped textview with some text inside (which has to be dynamic, based on some results retrieved from server). Up to now I extended TextView class implementing draw(Canvas canvas) method, I turned out into drawing the shape, but when I add my textView in xml and I try to add some text, the text simpy does not appear.
Here is my custom view:
public class ParallelogramTextView extends TextView {
Paint mInnerPaint;
public ParallelogramTextView(Context context) {
super(context);
init();
}
public ParallelogramTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
public ParallelogramTextView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
mInnerPaint = new Paint();
mInnerPaint.setAntiAlias(true);
mInnerPaint.setColor(Color.RED);
mInnerPaint.setStyle(Paint.Style.FILL);
mInnerPaint.setTextSize(20f);
}
#Override
public void draw(Canvas canvas) {
super.draw(canvas);
Path path = new Path();
path.moveTo(getWidth(),0);
path.lineTo(getWidth()/10, 0);
path.lineTo(0, getHeight());
path.lineTo(getWidth() - (getWidth()/10),getHeight());
path.lineTo(getWidth(), 0);
canvas.drawPath(path, mInnerPaint);
}
}
And here my xml:
<ParallelogramTextView
android:layout_width="200dp"
android:layout_height="40dp"
android:layout_gravity="center"
android:text="Test"
android:gravity="center"
android:textColor="#color/colorPrimary"
android:id="#+id/parallelogramTextView" />
I don't understand why text is not showing. Someone can help me?
Thanks in advance
I found a solution changing completely approach, I created a drawable representing a parallelogram shape using Vector and I used it as background for a normal TextView.
Don't know if it is best practice, but it worked for me.
Here the code of the drawable:
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="200dp"
android:height="50dp"
android:viewportWidth="200"
android:viewportHeight="50">
<path android:fillColor="#android:color/holo_red_dark"
android:pathData="M 200 0 L 20 0 L 0 50 L 180 50 L 200 0" />
</vector>
Related
I'm facing this weird problem where I have a custom view (with custom drawing) overriding ToggleButton, and for some reason overriding the onDraw and draw methods do not prevent the parent class from drawing a part of it, which makes my view look like it's glitched.
This bug seems to be happening only with API level 25, on a physical device or on the emulator.
Using the following code for my custom toggle Button:
public class CustomToggleButton extends ToggleButton {
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
public CustomToggleButton(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
public CustomToggleButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public CustomToggleButton(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomToggleButton(Context context) {
super(context);
}
#Override
protected void onDraw(Canvas canvas) {
//nope, not drawing anything
}
#Override
public void draw(Canvas canvas) {
//nope, not drawing anything
}
}
And the following simple XML layout:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="top|center_horizontal"
android:text="Bottom left: buggy custom ToggleButton.\nBottom right: regular ToggleButton." />
<test.com.togglebuttonbug.CustomToggleButton
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_gravity="bottom|left"
android:textOff="B"
android:textOn="A" />
<ToggleButton
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_gravity="bottom|right"
android:textOff="B"
android:textOn="A" />
</FrameLayout>
The result is the following:
If you look carefully at the screenshot, you can see that for the phone on the right, at the bottom left, instead of having nothing like the empty draw methods should do, you can see a piece of gray drawing.
Would anybody have an idea of what could be causing this? Is that a bug on Android N?
I have a TextView that doesn't align its text top and it just cuts it out, this is my xml structure:
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="30dp"
android:layout_marginLeft="45dp"
android:layout_marginRight="45dp" >
<CheckBox
android:id="#+id/privacyBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:button="#drawable/login_checkbox" />
<com.test.test.TopAlignedTextView
android:id="#+id/privacyText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:gravity="top"
android:includeFontPadding="false"
android:text="Ho preso visione e acconsento al trattamento dei dati personali ai sensi dell’art. 13 d. lgs. 196/2003"
android:textColor="#color/lowBlack"
android:textSize="14sp" />
</LinearLayout>
Where com.test.test.TopAlignedTextView is a class i've created in order to programmatically set the vertical alignment top, this is the code:
class TopAlignedTextView extends TextView {
// Default constructor when inflating from XML file
public TopAlignedTextView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
// Default constructor override
public TopAlignedTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs);
setIncludeFontPadding(false); //remove the font padding
setGravity(getGravity() | Gravity.TOP); //make sure that the gravity is set to the top
}
/*This is where the magic happens*/
#Override
protected void onDraw(Canvas canvas){
TextPaint textPaint = getPaint();
textPaint.setColor(getCurrentTextColor());
textPaint.drawableState = getDrawableState();
canvas.save();
//converts 5dip into pixels
int additionalPadding = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 5, getContext().getResources().getDisplayMetrics());
//subtracts the additional padding from the top of the canvas that textview draws to in order to align it with the top.
canvas.translate(0, -additionalPadding);
if(getLayout() != null)
getLayout().draw(canvas);
canvas.restore();
}
}
And this is the result I get:
The text gets cut off both from top and bottom and I have no idea on how to fix this
I have found a lot of posts about rounded rect for ImageViews in Android.
Currently I am using this solution: How to make an ImageView with rounded corners?
However, with various bitmap sizes, the rounded corner varies heavily depending on the sources size. I need constant rounded corners throughout the app, not depending on the bitmap size.
Does anyone know a solution to that?
this RoundedImageView Library works for me. I just set the corner radius as a dimension in the dimens.xml file and go from there with
<com.makeramen.RoundedImageView
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/imageView1"
android:src="#drawable/photo1"
android:scaleType="centerCrop"
app:corner_radius="#dimen/mycorner_radius_in_dp"
app:border_width="2dip"
app:border_color="#333333"
app:round_background="true"
app:is_oval="true" />
it doesnt care about the image size
make a java file which you will use to create circular view.
public class CircularImageView extends ImageView {
//you can change the radius to modify the circlur shape into oval or rounded rectangle
public static float radius = 100.0f;
public CircularImageView(Context context) {
super(context);
}
public CircularImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CircularImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected void onDraw(Canvas canvas) {
Path clipPath = new Path();
RectF rect = new RectF(0, 0, this.getWidth(), this.getHeight());
clipPath.addRoundRect(rect, radius, radius, Path.Direction.CW);
canvas.clipPath(clipPath);
super.onDraw(canvas);
}
}
After this use this java file in your layout like this:
<com.yourpackagename.CircularImageView
android:id="#+id/logo_ngo"
android:layout_width="50dp"
android:layout_height="50dp"
android:background="#drawable/circle"
android:src="#drawable/file_logo"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:contentDescription="#string/content_description"
android:layout_margin="#dimen/medium_margin"
android:scaleType="centerCrop"/>
Here file_logo is imagefile AND circle is filename which you will use as xml below:
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android1="http://schemas.android.com/apk/res/android"
android1:shape="oval">
<stroke android1:width="1dp"
android1:color="#000" >
</stroke>
<size
android1:width="50dp"
android1:height="50dp" >
</size>
<corners android1:radius="1dp" >
</corners>
</shape>
This worked for me, if anyone is having better solution kindly share yours too.
I have an ImageView and I would like to draw dinamically another images on my base ImageView.
In this image for example I have a tree and I would like to draw image of people
Any suggestions to start?
yes my problem is like #Tsunaze say:
I have a tree, and I want to put heads on it,
XML :
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<ImageView
android:id="#+id/iv_tree"
android:scaleType="fitXY"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:adjustViewBounds="true"
android:src="#drawable/my_tree" />
</RelativeLayout>
MyView.java :
public MyView extends View{
private Bitmap head_1, head_2;
public MyView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.context = context;
init();
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
init();
}
public MyView(Context context) {
super(context);
this.context = context;
init();
}
private void init(){
head_1= BitmapFactory.decodeResource(context.getResources(),
R.drawable.head_1);
head_2= BitmapFactory.decodeResource(context.getResources(),
R.drawable.head_2);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(head_1, coordinateX_head_1, coordinateY_head_1, null);
canvas.drawBitmap(head_2, coordinateX_head_2, coordinateY_head_2, null);
}
}
You choose the coordinate you want, you can even use function like canvas.getWidth() or canvas.getHeight(). Pose yourself as a painter. Good luck.
What you have to do is create a class that extends from ImageView, set the default parameters that you want as usual and override the on draw method, this method will give you the chance to get a reference to the canvas and draw bitmaps or pretty much anything you want, but remember to call first super.onDraw to keep your default configuration and overlay your new images.
There's plenty of tutorials on how to use canvas, so now you have the proper path to take, hope this helps.
Regards
setBackgroundResource to ImageView and use setImageResource over it.
Ex :
imageView.setBackgroundResource(R.id.backgroundTree);
imageView.setImageResource(R.id.allPeople);
EDIT :
If you want multiple images to be overlayed, check this example.
You can also use RelativeLayout and add ImageView inside it programmatically.
<RelativeLayout>
<ImageView/>
<ImageView/>
<ImageView/>
<ImageView/>
</RelativeLayout>
I have a vertical LinearLayout with two TextView inside it. The former contains a static text property (it's text never change) and the last contains a regressive timer. The image below shows both items:
I want to eliminate the blank space that both texts have both top and bottom. I've tried several approaches...
android:includeFontPadding="false"
android:lineSpacingMultiplier="1"
android:lineSpacingExtra="0dp"
android:paddingTop="0dp"
android:paddingBottom="0dp"
android:layout_marginTop="0dp"
android:layout_marginBottom="0dp"
...but none of them removed the space above the text. How can I make both texts close to each other without any extra space?
PS: I've found this similar question, but no one answered it.
Full layout code:
<LinearLayout
android:id="#+id/boxTime"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="20dp" >
<TextView
android:id="#+id/textRemainingTime2"
android:layout_width="wrap_content"
android:layout_heigh="wrap_content"
android:layout_gravity="center"
android:gravity="center_horizontal"
android:textSize="70sp"
android:includeFontPadding="false"
android:lineSpacingMultiplier="1"
android:lineSpacingExtra="0dp"
android:paddingTop="0dp"
android:paddingBottom="0dp"
android:layout_marginTop="0dp"
android:layout_marginBottom="0dp"
android:text="#string/title" />
<TextView
android:id="#+id/textRemainingTime"
android:layout_width="wrap_content"
android:layout_heigh="wrap_content"
android:layout_gravity="center"
android:gravity="center_horizontal"
android:includeFontPadding="false"
android:lineSpacingMultiplier="1"
android:lineSpacingExtra="0dp"
android:paddingTop="0dp"
android:paddingBottom="0dp"
android:layout_marginTop="0dp"
android:layout_marginBottom="0dp"
android:textSize="107sp"
android:text="#string/timer" />
</LinearLayout>
Try using negative margins. It may take a bit of playing with the numbers to get it right, but I've done it before and it worked out well.
android:layout_marginTop="-5dp"
By default, a TextView includes some padding to leave space for accent characters. You can turn that off with:
android:includeFontPadding="false"
or
textView.setIncludeFontPadding(false)
Make baseline of the text equal to the bottom of the TextView.
public class BaselineTextView extends TextView {
public BaselineTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
protected void onDraw(Canvas canvas) {
int yOffset = getHeight() - getBaseline();
canvas.translate(0, yOffset);
super.onDraw(canvas);
}
}
NOTE: To avoid chopping off descenders call setClipChildren(false) on your TextView's parent ViewGroup (android:clipChildren="false" in XML).
If you set includeFontPadding to false it helps.
android:includeFontPadding="false"
but if you know you don't have any descenders because you set
android:textAllCaps="true"
or you know there are no characters which have descender, you can make a custom TextView and set the height to the baseline.
public class ExTextView extends TextView {
public ExTextView(Context context) {
this(context, null);
}
public ExTextView(Context context, #Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public ExTextView(Context context, #Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
public ExTextView(Context context, #Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
#Override
protected void onDraw(Canvas canvas) {
setHeight(getBaseline()); // <--- Shrink size to baseline
super.onDraw(canvas);
}
}
The source code is included in my UiComponents test app.
https://github.com/landenlabs/UiComponents
Just use below, nothing else required.
android:includeFontPadding="false"
if you want some variations in line gap then use :
android:lineSpacingExtra
negative margins will do the trick
Since my requirement is override the existing textView get from findViewById(getResources().getIdentifier("xxx", "id", "android"));, so I can't simply try onDraw() of other answer.
But I just figure out the correct steps to fixed my problem, here is the final result from Layout Inspector:
Since what I wanted is merely remove the top spaces, so I don't have to choose other font to remove bottom spaces.
Here is the critical code to fixed it:
Typeface mfont = Typeface.createFromAsset(getResources().getAssets(), "fonts/myCustomFont.otf");
myTextView.setTypeface(mfont);
myTextView.setPadding(0, 0, 0, 0);
myTextView.setIncludeFontPadding(false);
The first key is set custom font "fonts/myCustomFont.otf" which has the space on bottom but not on the top, you can easily figure out this by open otf file and click any font in android Studio:
As you can see, the cursor on the bottom has extra spacing but not on the top, so it fixed my problem.
The second key is you can't simply skip any of the code, otherwise it might not works. That's the reason you can found some people comment that an answer is working and some other people comment that it's not working.
Let's illustrated what will happen if I remove one of them.
Without setTypeface(mfont);:
Without setPadding(0, 0, 0, 0);:
Without setIncludeFontPadding(false);:
Without 3 of them (i.e. the original):
Negative Margins would do the work. You can set it by two methods -
1) by xml - set the android:Layout_marginTop="-10dp" field negative
2) by java (Programmatically) - set the topMargin field of LayoutParams to negative.
you should change the height of TextView and maybe change android:gravity="bottom"
height is between textsize and size of textView with Wrapcontent.
public class MyTextViewBounder extends TextView {
public MyTextViewBounder(Context context) {
super(context);
}
public MyTextViewBounder(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyTextViewBounder(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//test kích thước thực tế với kích thước của Textview bao quanh text của nó như thế nào
int width, height;
Paint iPaint;
Rect iRect = new Rect();
iPaint = new Paint();
iPaint.setTextSize(13);
iPaint.setTextAlign(Paint.Align.CENTER);
//call below code outsite
//this.setText("Hung");
//this.setTextSize(TypedValue.COMPLEX_UNIT_PX,13);
//this..setIncludeFontPadding(false); //height from 18px down to 15px
iPaint.getTextBounds("Hung",0,4,iRect); //width = 34px, height = 12px
width = this.getWidth(); //= 30px
height = this.getHeight(); //= 18px
width = this.getMeasuredWidth(); //=30px
height = this.getMeasuredHeight(); //= 18px
width = iRect.width(); //34px
height = iRect.height(); //12 px
}
}