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
}
}
Related
I am using a TextView which has to rotate at angle at 35 degrees. I have successfully created a rotated textview but I can't fill the complete screen. Basically I want to complete 2 objectives-
1)Make the textview occupy the whole screen
currently it is showing it like this-
I wanna fill the space left in the top left corner. I covered the other three corners by the help of #Alexandre's answer. #Thanks Alexandre.
CustomTextView.java
public class CustomTextView extends android.support.v7.widget.AppCompatTextView {
public CustomTextView(Context context) {
super(context);
}
public CustomTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(widthMeasureSpec*2, heightMeasureSpec*3);
}
}
Layout
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/linearLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:orientation="vertical">
<com.dakshansh.partytimevendorsapp.CustomTextView
android:id="#+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:rotation="-35"
<!--Hope I don't need to change text.Text is too much more.-->
android:text="Galleries" />
</LinearLayout>
2)Make the text justified
As you can see my text is left aligned & as I am trying to create a pattern, I would require the text to be justified
One solution would be to create a CustomTextView that extends TextView overriding [onMeasure](https://developer.android.com/reference/android/view/View.html#onMeasure(int, int)).
For example :
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(widthMeasureSpec*2, heightMeasureSpec*2);
}
This would make your textView 4 times bigger filling the white spaces.
PS: I haven't tried this code.
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
My problem is, when i turn on a setting in the developer options to see view bounds, i can see that the orange "20" text wraps much larger space than it is requried. (top and bottom)
I tried to set: android:includeFontPadding="false" but it is just simple push up the content, leaving a big empty space bottom of the text's container.
How can i remove the extra space?
XML:
<LinearLayout
android:id="#+id/topDash"
android:layout_width="180dp"
android:layout_height="180dp"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:background="#drawable/circle_gray"
android:orientation="vertical" >
<TextView
android:id="#+id/RobotoTextView02"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="#string/sog_C"
android:textColor="#color/blue_medium"
android:textSize="20sp" />
<TextView
android:id="#+id/RobotoTextView01"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:text="20"
android:textColor="#color/orange"
android:textSize="100sp" />
<TextView
android:id="#+id/robotoTextView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="KM/H"
android:textColor="#color/gray_darker"
android:textSize="24sp" />
</LinearLayout>
Very nice question. I'm not sure that it possible to do it only in XML and without setting any hard coded value for scrollY property, but I implemented a small custom class without hard coded values, which you can use without any modifications in other places. In such situations onMeasure method always come to help :) I use default font here. If you use different typeface, call textPaint.setTypeface() and set it before textPaint.getTextBounds statement.
public class CustomTextView extends TextView {
private int newWidth;
private int newHeight;
public CustomTextView(Context context) {
super(context);
}
public CustomTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if(newHeight == 0) {
Rect textBounds = new Rect();
Paint textPaint = new Paint();
textPaint.setTextSize(getTextSize());
textPaint.getTextBounds(getText().toString(), 0, getText().length(), textBounds);
int descent = (int) textPaint.descent();
newWidth = textBounds.width();
newHeight = textBounds.height() - 2 * descent;
setScrollY(descent);
}
setMeasuredDimension(newWidth, newHeight);
}
}
But this solution is only good for numbers, why only for numbers, because of descent, and that's why we cant remove that extra space ony inside the XML, it is a font property
I am reopening a question that was asked two years (and yes, I tried all the answers but there was no joy). The question asked two years ago: ImageButton: Force square icon (height = WRAP_CONTENT, width = ?)
I am faced with the same situation where I am attempting to align a Button (with a background image) with an EditText. The following is what I am trying to accomplish:
The RelativeLayout I am using is:
<EditText
android:id="#+id/search_entry"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="#dimen/search_layout_height"
android:layout_marginLeft="#dimen/search_layout_left"
android:padding="#dimen/small_padding"
android:background="#drawable/search_box"
android:inputType="text|number"
android:textSize="#dimen/small_textsize"
android:hint="#string/search_for_hint"
android:textColorHint="#color/mdgray"
android:imeOptions="actionSend" />
<Button
android:id="#+id/search_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="#id/search_entry"
android:layout_alignTop="#id/search_entry"
android:layout_toRightOf="#id/search_entry"
android:adjustViewBounds="true"
android:scaleType="centerInside"
android:background="#drawable/search_btn" />
However, what I am ending up with is:
As you can see, it wants to stretch laterally.
Thoughts on how to make sure the button stays square?
You can use an ImageButton and make a class that extends ImageButton that will override the onMeasure method of it where in there you can make the background as a square using its background image's minimum size as the width and hieght to form a perfect square that will never deform the image.
example:
public class ImageViewPefectSquare extends ImageButton{
public ImageViewPefectSquare(Context context) {
super(context);
}
public ImageViewPefectSquare(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ImageViewPefectSquare(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int measuredWidth = getDefaultSize(getSuggestedMinimumWidth(),
widthMeasureSpec);
int measuredHeight = getDefaultSize(getSuggestedMinimumHeight(),
heightMeasureSpec);
// Ensure this view is always square.
int min = Math.min(measuredHeight, measuredWidth);
setMeasuredDimension(min, min);
}
}
what it is doing is that it will calculate for the minimum size of the image and use it as the width and height to make it a perfect square.
Use it as xml:
<com.youpackage.ImageViewPefectSquare
android:id="#+id/search_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="#id/search_entry"
android:layout_alignTop="#id/search_entry"
android:layout_toRightOf="#id/search_entry"
android:adjustViewBounds="true"
android:scaleType="centerInside"
android:background="#drawable/search_btn" />
This is because you are using Wrap_content you need to instead use an actual value if you want to keep an aspect ratio 1:1. If you want it to scale properly for all devices I would say in java code define the screen size and use the to calculate the width and height of the image for example:
button.setWidth(screenWidth/6);
button.setHeight(screenWidth/6);
I'm having a lot of trouble trying solve the issue of having a static height scrollable area within a layout. I have three long lists that need to be displayed on the same screen and it would be entirely impractical to display all of the entries sequentially because then if you want to skip a category you need to scroll past possibly hundreds of entries.
Assume I have a scroll view with a Linear Layout inside of it, I want this to take up say, 250dp height on the screen at max and be independently scrollable once populated with more entries than can fit in 250dp's space.
What I have now is:
<ScrollView
android:minWidth="25px"
android:minHeight="150px"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="#+id/XXXXXXX"
android:scrollbars="vertical">
<LinearLayout
android:orientation="vertical"
android:minWidth="25px"
android:minHeight="25px"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="#+id/XXXXXX" />
</ScrollView>
When populated, the scrollview and linearlayout just stretch as long as they needs to to fit the content and displays all of it instead of having a "window" of 250dp/px (any measurment would be nice) with the content scrollable within it.
I'm new to the android platform, so perhaps the answer is obvious and I just didn't understand the language, but any help would be greatly appreciated!
Thank you
--- SOLVED:
Put a linearLayout outside of the ScrollView with the height.
With some help from this answer I managed to wrap up a very basic ScrollView component you can use for this case:
Create a custom class extending a ScrollView and do the following modifications:
public class MaxHeightScrollView extends ScrollView {
private int maxHeight;
public MaxHeightScrollView(Context context) {
super(context);
}
public MaxHeightScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public MaxHeightScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
public MaxHeightScrollView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
if (attrs != null) {
TypedArray styledAttrs = context.obtainStyledAttributes(attrs, R.styleable.MaxHeightScrollView);
maxHeight = styledAttrs.getDimensionPixelSize(R.styleable.MaxHeightScrollView_maxHeight, 200); //200 is a default value
styledAttrs.recycle();
}
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
heightMeasureSpec = MeasureSpec.makeMeasureSpec(maxHeight, MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
And then one minor thing left is to declare your styleable in the attrs.xml file of your values folder(If you don't have one, just create an xml file with this name in the values folder of your project's res folder). Add the following lines there:
<declare-styleable name="MaxHeightScrollView">
<attr name="maxHeight" format="dimension" />
</declare-styleable>
And use your new ScrollView as follows:
<com.yourpackage.MaxHeightScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:maxHeight="300dp">
</com.yourpackage.MaxHeightScrollView>
Credits go to whizzle for quickly wrapping this up!
My simple solution.
Set ScrollView heigh in xml:
android:layout_height="wrap_content"
Add this code to set Max Height to 200 if current measured Height is > 200
sv.measure(0, 0);
if (nsv.getMeasuredHeight() > 200) {
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, 200);
sv.setLayoutParams(lp);
}
ScrollView in my example is into LinearLayout, so I used LinearLayout.LayoutParams.
What you need is a maxHeight. But since views do not support it, you have to use a workaround.
Check out this answer:
https://stackoverflow.com/a/13811461/770467
Add a layout around your ScrollView with fixed height