I have a TextView with multiple lines. How can I determine the space at the end to know if a view fits in there?
Example:
--------------------
| I am a multiline |
| text that has |
| space at the |
| end. <View>|
--------------------
--------------------
| I am a multiline |
| text that has |
| not enough space |
| at theeee end. |
| <View>|
--------------------
So I want my view to be in the bottom right corner, it should not overlay the text, but right of it if there is enough space
Basically, you need to see where does the last line's right (y-coordinate) reaches, and then calculate if the other view can fit the rest of the space exists.
I did a sample here with 2 textviews, but it can be applied to any view you wish.
The xml is pretty straight farward, nothing out of the ordinary.
<?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">
<TextView
android:id="#+id/text1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="kasjdf as df asd aasdfasdff as dfa sd sdf as df asd fa sd fa sdf as dfanas,df askdjfasjdf lkajsldkf jlaksjdfajsdkfj alskdj fklasjdflkasjdlkfdflk ajskldf" />
<TextView
android:id="#+id/text2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:text="attached text"
android:textColor="#android:color/holo_blue_dark" />
</RelativeLayout>
The catch here, after text1 and text2 are drawn to in the layout, i'm calculating where does the last line of text1 reaches, and together with the width of text2 - see if it can fit the screen's width.
Only after text1 and text2 are drawn, i can check the width and right position, so i'm waiting for them both in setText2Position.
The catch here - adding rules to text2 according to the calculation described above.
If you have margins and padding to your views, it needs to be calculated as well fe, if text2 has padding, the check should be :
lastLineRight + text2.getWidth() + text2.getPaddingRight() + text2.getPaddingLeft() > screenWidth
public class MainActivity extends AppCompatActivity {
private boolean[] areBothViewsDrawn = {false, false};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final TextView text1 = (TextView) findViewById(R.id.text1);
final TextView text2 = (TextView) findViewById(R.id.text2);
text1.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
text1.getViewTreeObserver().removeGlobalOnLayoutListener(this);
areBothViewsDrawn[0] = true;
setText2Position(text1, text2);
}
});
text2.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
text2.getViewTreeObserver().removeGlobalOnLayoutListener(this);
areBothViewsDrawn[1] = true;
setText2Position(text1, text2);
}
});
}
private void setText2Position(TextView text1, TextView text2) {
if (!areBothViewsDrawn[0] || !areBothViewsDrawn[1])
return;
int lineCount = text1.getLayout().getLineCount();
float lastLineRight = text1.getLayout().getLineRight(lineCount - 1);
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int screenWidth = size.x;
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) text2.getLayoutParams();
if (lastLineRight + text2.getWidth() > screenWidth) {
//The width of the last line of text1 is too long for the text2 to fit, so text2 must be in another line
params.addRule(RelativeLayout.BELOW, text1.getId());
} else {
//The width of the last line of text1 and text2 smaller then the application's width, so text2 can be in the same line as text1
params.addRule(RelativeLayout.ALIGN_BOTTOM, text1.getId());
}
}
}
Here are some poc's for my code :
I think this question needs more context. (just curious to why you'd want to do this)
Something like this is possible and would be easier if the TextView had a set width/height defined in the XML. If you're just dynamically getting the information there's some steps you'd have to take to make sure you're getting the correct measurements.
One approach I'm thinking would be to get the entire TextView's width, and get the difference between that and the actual text's width (perhaps a combination of getLineCount()/getLineBounds(int, Rect?) and getTextScaleX()?). Then convert it to dp.
Related
Im trying to create LinearLayout programmaticaly and I would want to allow user to put number range.
Now it looks like that:
But when I try to enter more digits eg. 100, 101 or 3,50 it dissapears.
I guess there is not enough space for it to be shown, but I can't figure out what is wrong. Generally I don't want to move + and - buttons when the user enters some values so I guess it should be hardcoded. There would be up to 5-6 digits only, so I need space just for it, but as I said, I can't find the place, where I can change it as my changes eiter move entire layout or doesn't do anything.
Below is my code:
LinearLayout horizontalLayout = new LinearLayout(mContext);
LinearLayout titleLayout = new LinearLayout(mContext);
LinearLayout countLayout = new LinearLayout(mContext);
ImageButton buttonAdd = new ImageButton(mContext);
ImageButton buttonSub = new ImageButton(mContext);
TextView titleTextView = new TextView(mContext);
EditText countEditText = new EditText(mContext);
final int[] currentCount = {defaultValue};
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
LinearLayout.LayoutParams linearLayout = new LinearLayout.LayoutParams(0, LayoutParams.MATCH_PARENT, 1f);
LinearLayout.LayoutParams utilParams = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
horizontalLayout.setOrientation(LinearLayout.HORIZONTAL);
horizontalLayout.setLayoutParams(params);
utilParams.gravity = Gravity.CENTER_VERTICAL;
titleLayout.setOrientation(LinearLayout.HORIZONTAL);
titleLayout.setPadding(0, pxFromDp(mContext, 16),0, pxFromDp(mContext, 16));
titleLayout.setLayoutParams(linearLayout);
countLayout.setOrientation(LinearLayout.HORIZONTAL);
countLayout.setPadding(0, pxFromDp(mContext, 16),0, pxFromDp(mContext, 16));
countLayout.setLayoutParams(linearLayout);
utilParams.setMargins(0,0,pxFromDp(mContext, 16f),0);
titleTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP,16);
titleTextView.setText(title);
titleTextView.setLayoutParams(utilParams);
titleLayout.addView(titleTextView);
utilParams.setMargins(pxFromDp(mContext, 16f),0,pxFromDp(mContext, 16f),0);
buttonSub.setImageResource(R.drawable.ic_remove);
buttonSub.setLayoutParams(utilParams);
buttonSub.setBackgroundColor(mContext.getResources().getColor(R.color.fsm_survey_btn));
buttonSub.setColorFilter(ContextCompat.getColor(mContext, R.color.fsm_white), android.graphics.PorterDuff.Mode.SRC_IN);
countLayout.addView(buttonSub);
countEditText.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16);
countEditText.setText(String.valueOf(defaultValue));
countEditText.setLayoutParams(linearLayout);
countEditText.setGravity(Gravity.CENTER);
countLayout.addView(countEditText);
buttonAdd.setImageResource(R.drawable.ic_add_24);
buttonAdd.setLayoutParams(utilParams);
buttonAdd.setBackgroundColor(mContext.getResources().getColor(R.color.fsm_survey_btn));
buttonAdd.setColorFilter(ContextCompat.getColor(mContext, R.color.fsm_white), android.graphics.PorterDuff.Mode.SRC_IN);
countLayout.addView(buttonAdd);
horizontalLayout.addView(titleLayout);
horizontalLayout.addView(countLayout);
What you can do is to create separate LinearLayout.LayoutParams for the edittext and add addTextChangedListener to that edit text and on onTextChanged
write switch statement to increase the weight of the edittext on increase of length of the input number.
I am trying to program the margin of the ImageView inside the ConstraniLayout2 with this code
ConstraintLayout.LayoutParams newLayoutParams = (ConstraintLayout.LayoutParams)
imageView.getLayoutParams();
newLayoutParams.topMargin = 140;
newLayoutParams.leftMargin = 400;
newLayoutParams.rightMargin = 0;
newLayoutParams.bottomMargin = 0;
imageView.setLayoutParams(newLayoutParams);
With this code I program the site of the imageView but of the entire screen of the smartphone.
How can I program the imageView to switch places with the constrainLayout2 references?
You can also try to set the margin using ConstraintSet.
Below is a snippet you can try
val constraintSet = ConstraintSet()
constraintSet.clone(constraintLayoutId)
val marginTop = context.getDimension(10f)
constraintSet.setMargin(R.id. imageView, ConstraintSet.TOP, marginTop)
constraintSet.applyTo(constraintLayoutId)
fun Context.getDimension(value: Float): Int {
return TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, value, this.resources.displayMetrics).toInt()
}
I'm writing an image gallery with horizontal scrolling. Images must be added programatically.
I use a custom horizontal scroll view to process and add images as in the following code:
public void setViewList(Integer linearLayoutId, Integer[] imageIdList,
Activity activity) {
displayMetrics = ImageUtils.getDisplayMetric(activity);
LinearLayout ll = (LinearLayout) findViewById(linearLayoutId);
for (Integer imgId : imageIdList) {
ImageView imageView = new ImageView(getContext());
imageView.setImageResource(imgId);
imageView.setScaleType(ImageView.ScaleType.MATRIX);
Integer[] displayMetrics = ImageUtils.getDisplayMetric(activity);
ImageUtils.scaleImage(imageView, displayMetrics[0], displayMetrics[1]);
Integer[] dstDimension = ImageUtils.createDimension();
ImageUtils.getImageSize(imageView, dstDimension);
getImageSizeList().add(dstDimension);
ll.addView(imageView);
}
}
As you can see I scale an image with use the following method (call ImageUtils.scaleImage(imageView, displayMetrics[0], displayMetrics[1])):
public static void scaleImage(ImageView imView, int screenWidth, int screenHeight) {
Drawable temp = imView.getDrawable();
Bitmap imBitmap = ((BitmapDrawable)temp).getBitmap();
int imWidth = imBitmap.getWidth();
int imHeight = imBitmap.getHeight();
float xScale = ((float) screenWidth) / imWidth;
float yScale = ((float) screenHeight) / imHeight;
float scale = xScale <= yScale ? xScale : yScale;
Matrix scaleMatrix = new Matrix();
scaleMatrix.postScale(scale, scale);
Bitmap scBitmap = Bitmap.createBitmap(imBitmap, 0, 0, imWidth, imHeight, scaleMatrix, true);
BitmapDrawable scDrBitmap = new BitmapDrawable(imView.getResources(), scBitmap);
imView.setImageDrawable(scDrBitmap);
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT
);
layoutParams.gravity = Gravity.CENTER;
imView.setLayoutParams(layoutParams);
}
My main.xml layout is pretty simple:
<?xml version="1.0" encoding="utf-8"?>
<android.lessons.custom_horizontal_scroll.CustomHorizontalScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/horizontalScrollView"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<LinearLayout android:orientation="horizontal"
android:id="#+id/mainLayout"
android:layout_gravity="center"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</android.lessons.custom_horizontal_scroll.CustomHorizontalScrollView>
Where the android.lessons.custom_horizontal_scroll.CustomHorizontalScrollView is implementation of a simple custom HorizontalScrollView.
For testing I use Samsung Galaxy S3 and images with the following resolution: (1) 1290*990 (2) 1221*900. What it looks like:
In many cases everything is displayed fine but from time to time I get the wrong result: the first image divides a screen with the following one at app start time and I don't have any idea why it happens.
Thanks for help.
I think you should use ViewPager from the support library v4 rather than this custom horizontal scroll view in this case. It's designed for that purpose.
Here is how to use it https://developer.android.com/training/animation/screen-slide.html.
The problem was resolved with use gravity = Gravity.FILL_HORIZONTAL | Gravity.CENTER_VERTICAL, that i set programmatically on a image view (method ImageUtils.scaleImage).
I am trying to add multiple components into linear layout programatically. Here are the codes:
private View createCalloutView(Graphic graphic) {
LinearLayout ret = new LinearLayout(this);
ret.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT));
TextView reportContent = new TextView(this);
reportContent.setText(eventName + "\n" + eventBy + "\n" + eventAddress + "\n" + eventDesc
+ "\n" + eventDate + "\n" + eventTime);
reportContent.setTextColor(Color.BLACK);
reportContent.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 12);
reportContent.setPadding(1, 0, 1, 0);
Button viewDtlEventBtn = new Button(this);
viewDtlEventBtn.setText("View details");
viewDtlEventBtn.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,
LayoutParams.WRAP_CONTENT));
ret.addView(reportContent);
ret.addView(viewDtlEventBtn);
return ret;
}
With these codes, I only manged to see the textview and my button is missing. Any ideas? Thanks in advance.
that depends on how do you want to arrange the items in the LinearLayout. If you want to arrange the button next to the TextView, then, probably, the button width should be WRAP_CONTENT instead of FILL_PARENT. If you want to show the button under the TextView, then, your LinearLayout should have vertical as orientation (default is horizontal). Imo, the easiest way is to have your layout defined in a xml file. At least you can see the output at compile time, and use an inflater to retrieve the View's object at run time
The default orientation of linear layout is horizontal. You need to set the orientation first.
LinearLayout ret = new LinearLayout(this);
ret.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT));
ret.setOrientation(LinearLayout.VERTICAL);
This will solve your problem of missing button.
You have forgot to set Layout Orientation for Linear Layout, just set it as below:
ret.setOrientation(LinearLayout.VERTICAL);
I have hit a problem when trying to align my text to the top of a text view dynamically. I have a method that creates textviews dynamically. I have set the gravity of the text view to Gravity.TOP. Which a believe should place the text at the very top of the textView object. However when I run the project there is a gap of about 2 lines of text from the top of the object. I can work around this by changing the height of the textView but I would rather it loaded in an set the size depending on how much text there is too load into the textView.
Here is my function, it works well and does what it is supposed to do:
public void addItems(LinearLayout page,int id,String text,int row){
LinearLayout item = new LinearLayout(this);
item.setLayoutParams(new ViewGroup.LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.WRAP_CONTENT));
TextView itemNum = new TextView(this);
//itemNum.setLayoutParams(new ViewGroup.LayoutParams(50,50));
itemNum.setWidth(50);
itemNum.setTextSize(40);
itemNum.setTextAppearance(getApplicationContext(), R.style.large_text);
itemNum.setLeft(0);
itemNum.setText(row+":");
LayoutParams numParams = new LinearLayout.LayoutParams(70, 70);
numParams.setMargins(25, 0, 0, 0);
TextView itemDetails = new TextView(this);
itemDetails.setLayoutParams(new ViewGroup.LayoutParams(150,LayoutParams.WRAP_CONTENT));
itemDetails.setText(text);
itemDetails.setWidth(100);
itemDetails.setLeft(5);
itemDetails.setRight(5);
itemDetails.setTop(0);
itemDetails.setVisibility(View.VISIBLE);
itemDetails.setGravity(itemDetails.getGravity() | Gravity.TOP);
itemDetails.setPadding(0,0,0,0);
Button delete = new Button(this);
//delete.setLayoutParams(new ViewGroup.LayoutParams(50,50));
delete.setText("Delete");
LayoutParams btnParams = new LinearLayout.LayoutParams(70, 70);
btnParams.setMargins(0, 0, 15, 0);
item.addView(itemNum,numParams);
item.addView(itemDetails);
item.addView(delete,btnParams);
page.addView(item);
Log.d("Loop","Loop is adding function in");
}
If anybody can see where I have gone wrong I would really appreciate it. The method above may seem very long winded but I am new to Java.
Not sure if it will help but here is my string to show in the textView:
String formatText = lat + ", " + lng + " /n" + result;