Android TextView baseline related margin - android

I need to position a TextView the way its baseline is 20dp from the bottom of the container.
How can I achieve this?
The layout with bottom margin or padding produces the same result.
I would like to make the text 'sit' on the purple line.
When I write 'sit' I mean, the 'wert' should touch the line, not 'q...y'.
The padding / margin is equal to the purple square size:

If you still need it, I wrote custom method, to not create lots of custom views. It works for me with TextView:
public static void applyExistingBotMarginFromBaseline(View view) {
final int baseline = view.getBaseline();
final int height = view.getHeight();
final ViewGroup.MarginLayoutParams marginLayoutParams;
try {
marginLayoutParams = ((ViewGroup.MarginLayoutParams) view.getLayoutParams());
} catch (ClassCastException e) {
throw new IllegalArgumentException("Applying margins on a view with wrong layout params.");
}
final int baselineMarginValue = baseline + marginLayoutParams.bottomMargin;
marginLayoutParams.bottomMargin = baselineMarginValue - height;
view.setLayoutParams(marginLayoutParams);
}
You can apply it when view is measured already, so like this:
final TextView title = (TextView) findViewById(R.id.title);
title.post(new Runnable() {
#Override public void run() {
Utils.applyExistingBotMarginFromBaseline(title);
}
});
Also you can use databinding framework and write your own custom BindingAdapter with a bit customized method, to use it from xml.

Your problem is not the padding/margin referenced to the parent, I think is about your font, I recommend you to change the fontFamily:"yourStyle"
even worst you have to re-difine your own font style which is explained here Custom fonts and XML layouts (Android) or Set specific font in a styles.xml

Related

Android CollapsingToolbarLayout with custom View

I'm following the Cheesesquare example project to understand the new design material library.
I'm wondering if there's a way to use a custom view (like Telegram) with ImageView, title and subtitle instead of the simple Title provided by CollapsingToolbarLayout widget.
Thanks.
I had the same problem and spend many hours trying to find a solution. My solution was to add the collapsing Views (ImageView and TextView) inside the CollapsingToolbarLayout and then handle the transition in code. This way it's more flexible and simpler than extending from CollapsingToolbarLayout.
First you'll need to add your Views inside the CollapsingToolbarLayout with the parallax properties:
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop:"80dp"
android:src="#drawable/icon"
app:layout_collapseMode="parallax"
app:layout_collapseParallaxMultiplier="0.8"/> //set vertical transition here
Then set the scaling of the Views with the help of an OnOffsetchangeListner:
private static final float SCALE_MINIMUM=0.5f;
appBarLayout.setOnWorkingOffsetChange(new ControllableAppBarLayout.OnWorkingOffsetChange() {
#Override
public void onOffsetChange(int offSet, float collapseDistance) {
imageView.setScaleX(1 + (collapseDistance * SCALE_MINIMUM));
imageView.setScaleY(1 + (collapseDistance * SCALE_MINIMUM));
textView.setScaleX(1 + (collapseDistance * SCALE_MINIMUM));
textView.setScaleY(1 + (collapseDistance * SCALE_MINIMUM));
// You can also setTransitionY/X, setAlpha, setColor etc.
}
});
Somehow the default offsetChangedListener didn't work properly for me (you probably still should try it with the default listener first), so I used the ControllableAppBarLayout from https://gist.github.com/blipinsk/3f8fb37209de6d3eea99 and added the following:
private OnWorkingOffsetChange onWorkingOffsetChange;
#Override
public void onOffsetChanged(AppBarLayout appBarLayout, int i) {
if (!isInEditMode()) {
onWorkingOffsetChange.onOffsetChange(i, (float) i / appBarLayout.getTotalScrollRange());
}
}
public void setOnWorkingOffsetChange(OnWorkingOffsetChange listener) {
this.onWorkingOffsetChange = listener;
}
public interface OnWorkingOffsetChange {
void onOffsetChange(int offSet, float collapseDistance);
}
The only problem is, that you would need to set
app:contentScrim="#00000000" (transparent)
for your CollapsingToolbarLayout, so your views are still visible when the toolbar is collapsed. If you really need the collapsing-background effect I'm sure you could "fake" this by setting the alpha of a background ImageView in the OffsetChangeListener. ;)
From the widget itself there doesn't seem to be a way to enable this directly, like it was possible to add custom views to the Toolbar.
What you could try to do however, is open the source of the CollapsingToolbarLayout.class and check out how the CollapsingTextHelper.class is used to have the title set. You could try to make your own widget by extending from the the CollapsingToolbarLayout.
These links can help you out with creating custom components/views, if you haven't created them before:
Custom Views, Custom Components
I haven't tried this yet, but it's actually something I was thinking about trying to achieve a similar solution as you are looking for. Steps I tihkn I would follow, so far:
Create custom attributes for subtitle settings in attrs.xml
Create your own MyCollapsingToolbarLayout by extending the original one.
Make sure to call super in the constructors, so the original component will stay intact.
Create a subtitleTextHelper by adding a new CollapsingTextHelper to your component.
Override onDraw to actually draw your subtitle.
Update the layout containing your CollapingsToolbarLayout with your subtitle attributes (default styling and such, maybe a fixed subtitle Text).
Apply the changes in the Activity containing your CollapsingToolbar. (Convert CollapsingToolbarlayout to MyCollapingsToolbarLayout, set subtitles, extra custom settings, etc).
Cross fingers, test.
Going to have a look at it now.
Going to edit Christopher's answer slightly to show how you can get your custom view to not disappear on collapse:
First you'll need to add your Views inside the CollapsingToolbarLayout with the parallax properties:
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop:"80dp"
android:src="#drawable/icon"
app:layout_collapseMode="parallax"
app:layout_collapseParallaxMultiplier="0.8"/> //set vertical transition here
Instead add the custom view's programmatically and it won't disappear on collapse. For example here is a view that contains a title and a subtitle:
final FrameLayout frameLayout = new FrameLayout(mActivity);
FrameLayout.LayoutParams frameLayoutParams = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT);
frameLayout.setLayoutParams(frameLayoutParams);
// Create new LinearLayout
final LinearLayout linearLayout = new LinearLayout(mActivity);
frameLayoutParams =new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, dpToPixels(78));
frameLayoutParams.gravity = Gravity.BOTTOM;
linearLayout.setLayoutParams(frameLayoutParams);
linearLayout.setOrientation(LinearLayout.VERTICAL);
// Add textviews
final TextView textView1 = new TextView(mActivity);
LinearLayout.LayoutParams linearLayoutParams =new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
frameLayoutParams.gravity = Gravity.BOTTOM;
textView1.setLayoutParams(linearLayoutParams);
textView1.setText("Title");
textView1.setTextColor(ContextCompat.getColor(mActivity, R.color.colorWhite));
textView1.setTextSize(TypedValue.COMPLEX_UNIT_SP, 40);
linearLayout.addView(textView1);
final TextView textView2 = new TextView(mActivity);
linearLayoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
textView2.setLayoutParams(linearLayoutParams);
textView2.setText("Subtitle");
textView2.setTextColor(ContextCompat.getColor(mActivity, R.color.colorWhite));
textView2.setTextSize(TypedValue.COMPLEX_UNIT_SP, 20);
linearLayout.addView(textView2);
frameLayout.addView(linearLayout);
collapsingToolbar.addView(frameLayout);
final float SCALE_MIN=0.4f;
AppBarLayout appBarLayout = (AppBarLayout) mActivity.findViewById(R.id.appBarLayout);
appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
#Override
public void onOffsetChanged(AppBarLayout appBarLayout, int offSet) {
float collapsedRatio = (float) offSet / appBarLayout.getTotalScrollRange();
linearLayout.setScaleX(1 + (collapsedRatio * SCALE_MIN));
linearLayout.setScaleY(1 + (collapsedRatio * SCALE_MIN));
FrameLayout.LayoutParams frameLayoutParams =new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, dpToPixels(78));
frameLayoutParams.gravity = Gravity.BOTTOM;
frameLayoutParams.setMargins(Math.round(dpToPixels(48) * (1+collapsedRatio)), 0, 0, Math.round(dpToPixels(15) * collapsedRatio));
linearLayout.setLayoutParams(frameLayoutParams);
// You can also setTransitionY/X, setAlpha, setColor etc.
}
});
/////
float lastCollapsedRatio = -2;
////
private int dpToPixels(int padding_in_dp){
final float scale = getResources().getDisplayMetrics().density;
int padding_in_px = (int) (padding_in_dp * scale + 0.5f);
return padding_in_px;
}

Animate view's width to match parent?

I want to create the following concept:
First expand the view to its parent's width (it's not the same).
Then expand the view to its parent's height.
I know I can create the sequence with AnimatorSet(). What I cannot find is what property/-ies to animate to create the result.
My thoughts for the width animation:
I would probably need to animate either two points which define left and right or alternatively animate the translation and the width.
I'm a bit confused, which properties would do the trick?
You'll need to define custom properties to do this (I know, silly). Height example:
public static final Property<View, Integer> PROPERTY_HEIGHT =
new Property<View, Integer>(Integer.class, "viewLayoutHeight") {
#Override
public void set(View object, Integer value) {
object.getLayoutParams().height = value.intValue();
object.requestLayout();
}
#Override
public Integer get(View object) {
return object.getLayoutParams().height;
}
};
Then use as a normal property:
ObjectAnimator.ofInt(view, PROPERTY_HEIGHT, minHeight, maxHeight);
You'll need to get the parent dimensions at runtime (perhaps using a ViewTreeObserver.OnGlobalLayoutListener).
I think that there is no need to complicate things, you can use width property first then followed by height in AnimatorSet, Your view gravity property will define in which direction view will expand ...

Resize elements in bar chart by multiplying with a factor

I am trying to create a bar chart in android where each bar consists of one Viewand one TextView.
I add these cells to a HorizontalScrollView. This works fine, all my bars appear.
Now I want to resize these bars(as they now all appear in full height) by multiplying them with a factor.
This is the activity class that i Use.
private ViewGroup linearScrollLayout;
private HorizontalScrollView hScrollView;
private ArrayList<NutrientCell> nutrientsData;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.box_plot);
this.hScrollView = (HorizontalScrollView) findViewById(R.id.horizontalScrollView1);
this.linearScrollLayout = (ViewGroup) this.hScrollView
.findViewById(R.id.linearScrollLayout);
try {
Intent intent = getIntent();
this.nutrientsData = (ArrayList<NutrientCell>) intent
.getSerializableExtra("nutrientsData");
//
} catch (Exception e) {
// TODO: handle exception
}
this.initChart();
}
private void initChart() {
for (NutrientCell c : this.nutrientsData) {
RelativeLayout rlt = (RelativeLayout) getLayoutInflater().inflate(
R.layout.hv_boxplot_cell, this.linearScrollLayout, false);
((TextView) rlt.findViewById(R.id.textView1)).setText(c
.getNutrientName().toString());
View v = ((View) rlt.findViewById(R.id.vv1));
v.setBackgroundColor(c.getColor());
this.linearScrollLayout.addView(rlt);
}
}
Now, in the loop found in initChart() I iterate over all elements in an ArrayList, each of which has a percentage variable. This is the variable I would like to multiply the height with.
I have tried to just multiply the height of the LayoutParams of the inflated RelativeLayout found in initChart but as this is called in onCreate(), its height property is not correct.
So how can I make sure that the inflated RelativeLayout I add to my View has a height corresponding to the percentage obtained from c(c.getPercentage())
What exactly is the percentage used for? If the percentage is used to scale the view based on it's initial size, you could probably use the view's setScaleY() method to change it's height.

Android TextView: can I stop text that is partially displayed from appearing

In my app I display several text views containing text of various length that is loaded in at run time. I do not know the dimensions of the text view or the length of the text until run time. Sometimes, when the text is long and the textview small some of the text is partially visible, for example:
I want to remove the partially visible text as it looks a bit naff, but I can't find a way to do this. Any help would be appreciated!
Thanks,
Dave
You can hard code the TextView height in a way that the second row of text will not be visible.
Or use:
android:maxLines , Makes the TextView be at most this many lines tall.
as suggested above.
Put your textviews in a scrollview layout.And specify a specific width to your textview and make the height wrap content.So that your text doesn't get cut.
This is how I did it. I ran this code after the activity had loaded by posting the method CheckTextIsVisible to the parent relativelayout's handler queue, otherwise the height of the textviews will not be known:
m_eventsLayout.Post(new Action(CheckTextIsVisible));
Then the method CheckTextIsVisible finds each textview with text in it, calculates the height of the font, works out how many lines can fit in the textview, and sets the number of maximum lines accordingly:
private void CheckTextIsVisible()
{
View view;
TextView tView;
Android.Text.TextPaint tPaint;
float height;
int heightOfTextView;
int noLinesInTextView;
for (int i = 0; i < m_eventsLayout.ChildCount; i++)
{
view = m_eventsLayout.GetChildAt(i);
if (view is TextView)
{
tView = (TextView)view;
if (tView.Text != "")
{
//calculate font height
tPaint = tView.Paint;
height = CalculateTextHeight(tPaint.GetFontMetrics());
//calculate the no of lines that will fit in the text box based on this height
heightOfTextView = tView.Height;
noLinesInTextView = (int)(heightOfTextView / height);
//set max lines to this
tView.SetMaxLines(noLinesInTextView);
}
}
}
}
private float CalculateTextHeight(Android.Graphics.Paint.FontMetrics fm)
{
return fm.Bottom - fm.Top;
}
This results in no partially visible text!

Make layout width equal height?

I want to have an ImageView with width=fill_parent, and the height should be whatever the width is. I'm not sure if there's a way to specify that in xml, is the only option to create my own ImageView-derived class?:
public class MyImageView extends ImageView {
// Just return whatever the current width is?
private int measureHeight(int measureSpec) {
return getWidth();
}
}
Is this the way to go, any other options? (I'm not sure if the above is even correct, not sure if the width measurement even takes place before the height measurement for example)
Thanks
You can get the width with the method
imageView.getMeasuredWidth();
So, you can set it's height
imageView.setLayoutParams(new LayoutParams(imageView.getMeasuredWidth(), imageView.getMeasuredWidth()));
Make layout height equal to the width:
The problem with digulino's answer (in my case at least) is that if you want to change the dimensions in the start, getMeasuredWidth() will return 0 because the views haven't been drawn yet.
You can still do it by using a Runnable() thread like this:
FrameLayout frame = (FrameLayout)findViewById(R.id.myFrame);
frame.post(new Runnable() {
#Override
public void run() {
RelativeLayout.LayoutParams lparams;
lparams = (RelativeLayout.LayoutParams) frame.getLayoutParams();
lparams.height = frame.getWidth();
frame.setLayoutParams(lparams);
frame.postInvalidate();
}
});
Important Note:
This example assumes your view is a FrameLayout inside a RelativeLayout. Change it accordingly for other layouts.

Categories

Resources