My application is cut off from the top side by the notch
Is there any specific solution to overcome this problem.
I am using the emulator Pixel 3 XL API 27
image for illustrstion
What should I do any code is there to increase the height of the top bar or status bar or should I increase the height of the title bar, but the title bar is still cut off
Any suggestion or code explanation
Try below solution
It is get size of notch as per device and set margin top to view So,it's fit in all device.
#Override
protected void onCreate(Bundle savedInstanceState) {
this.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
this.getWindow().setStatusBarColor(Color.TRANSPARENT);
super.onCreate(savedInstanceState);
setContentView(MainActivity.this, R.layout.activity_main);
/*------------ Check display cutout size and give top margin to toolbar -------------*/
setMarginTopAccordingDisplayCutout(context, yourTopMainView, convertDpToPixel(34), 0);
/*-----------------------------------------------------------------------------------*/
...
//your Code
}
private void setMarginTopAccordingDisplayCutout(Context context, View view, int extraTopWithoutCutout, int extraTopWithCutout) {
int statusBarHeight = 0;
int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
statusBarHeight = context.getResources().getDimensionPixelSize(resourceId);
}
if (statusBarHeight > convertDpToPixel(24)) {
final ViewGroup.MarginLayoutParams[] layoutParams = new ViewGroup.MarginLayoutParams[1];
layoutParams[0] = (ViewGroup.MarginLayoutParams) view.getLayoutParams();
layoutParams[0].topMargin = statusBarHeight + extraTopWithCutout;
view.setLayoutParams(layoutParams[0]);
//topbarlp.setMargins(0, statusBarHeight, 0, 0);
//Set above layout params to your layout which was getting cut because of notch
///topbar.setLayoutParams(topbarlp)
Log.e(TAG, "onCreate statusBarHeight :: " + statusBarHeight);
} else {
final ViewGroup.MarginLayoutParams[] layoutParams = new ViewGroup.MarginLayoutParams[1];
layoutParams[0] = (ViewGroup.MarginLayoutParams) view.getLayoutParams();
layoutParams[0].topMargin = extraTopWithoutCutout;
view.setLayoutParams(layoutParams[0]);
}
}
private int convertDpToPixel(float dp) {
DisplayMetrics metrics = Resources.getSystem().getDisplayMetrics();
float px = dp * (metrics.densityDpi / 160f);
return Math.round(px);
}
I hope this can help you!
Thank You.
I have an AppBarLayout with CollapsingToolbarLayout, two views below and ViewPager at the rest of the screen
<Coordinator>
<AppBarLayout>
// Toolbar stuff inside
<CollapsingToolbarLayout app:layout_scrollFlags="scroll|exitUntilCollapsed"/>
// Should collapse by design
<FirstButtonView app:layout_scrollFlags="scroll" />
<TabLayout app:layout_scrollFlags="scroll|exitUntilCollapsed">
</AppBarLayout>
<ViewPager app:layout_behavior="#string/appbar_scrolling_view_behavior"/>
</Coordinator>
With this layout it collapsed toolbar as expected, but both views are being pinned to the top
As i see in AppBarLayout class, when it calculates possible scroll, it iterates through child views until meet flag SCROLL_FLAG_EXIT_UNTIL_COLLAPSED=2, then breaks the loop
public final int getTotalScrollRange() {
if (this.totalScrollRange != -1) {
return this.totalScrollRange;
} else {
int range = 0;
int i = 0;
for(int z = this.getChildCount(); i < z; ++i) {
View child = this.getChildAt(i);
AppBarLayout.LayoutParams lp = (AppBarLayout.LayoutParams)child.getLayoutParams();
int childHeight = child.getMeasuredHeight();
int flags = lp.scrollFlags;
if ((flags & 1) == 0) {
break;
}
range += childHeight + lp.topMargin + lp.bottomMargin;
if ((flags & 2) != 0) {
range -= ViewCompat.getMinimumHeight(child);
break;
}
}
return this.totalScrollRange = Math.max(0, range - this.getTopInset());
}
}
Is it possible somehow to solve it?
Target design
Based on Documentation on using "SCROLL_FLAG_SCROLL", "If any sibling views before this one do not have this flag, then this value has no effect."
Hence the same flag has to be used with other siblings.
Is there any way I can adjust listview's height as of it's content height in xamarin.forms? I could successfully do it for ios but for android, I applied a solution that leads to slow layout rendering.
code
public class CustomListViewRenderer : ListViewRenderer
{
...
protected async override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
base.OnMeasure(widthMeasureSpec, heightMeasureSpec);
if(Element == null || ((CustomListView)Element).IsScrollable)
{
return;
}
var view = (CustomListView)Element;
if(!view.IsScrollable)
{
var mAdapter = nativeList.Adapter;
int totalHeight = 0;
int listWidth = nativeList.MeasuredWidth;
int listHeight = nativeList.MeasuredHeight;
if(totalCount == nativeList.Count)
{
//return;
}
for (int i = 0; i < mAdapter.Count; i++)
{
global::Android.Views.View mView = mAdapter.GetView(i, null, nativeList);
mView.Measure(MeasureSpec.MakeMeasureSpec(listWidth, MeasureSpecMode.Exactly),
MeasureSpec.MakeMeasureSpec(0, MeasureSpecMode.Unspecified));
totalHeight += (int)(mView.MeasuredHeight / Resources.DisplayMetrics.Density);
totalCount = i + 1;
}
ViewGroup.LayoutParams param = nativeList.LayoutParameters;
param.Height = totalHeight
+ (nativeList.DividerHeight * (mAdapter.Count - 1));
view.HeightRequest = param.Height;
}
}
}
This however does not always generate exact height for listview, sometimes leaving space at bottom. Moreover it creates a great delay in laying out the page where list view has been used.
Can anyone please help me with this?
Is there any way I can adjust listview's height as of it's content height in xamarin.forms?
You could using HasUnevenRows property to implement this feature :
HasUnevenRows – true/false value, rows have varying heights if set to true. Defaults to false.
Row heights don't have to be manually set once HasUnevenRows has been set to true, because the heights will be automatically calculated by Xamarin.Forms.
C# :
RowHeightDemoListView.HasUnevenRows = true;
XAML :
<ListView x:Name="RowHeightDemoListView" HasUnevenRows="true" />
I have a bitmap and below it is a time line.
As an example consider the right side layout of the FIGURE.
All the bottom timelines (1, 2, 3...) are in the same height from top.
The timeline is a textview which has fixed layout height and width as it is defined in xml
like timeline 1 is defined as:
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="#+id/HView"
android:layout_marginLeft="18dp"
android:layout_marginTop="345dp"
android:textSize="14sp"
android:text="1"
android:textColor="#000000" />
However the bitmap height and width can vary as it is done programatically.
So in certain cases, the bitmap height increases enough to overlap the timeline. In other words,
the vertical position of bitmap increases with respect to the vertical position of the timeline.
I want to get:
1) the ended vertical position of bitmap with respect to top of the screen.
2) the ended vertical position of timeline with respect to top of the screen.
I tried to do the following:
TextView bottomTimeLine = (TextView) view.findViewById(R.id.textView1);
bottomTimeLine.getHeight(); //returns 0.
bottomTimeLine.getBottom(); //returns 0.
ImageView img = new ImageView(getActivity());
img.setImageDrawable(getResources().getDrawable(R.drawable.disp_bg));
img.getHeight(); //returns 0.
img.getBottom(); //returns 0.
As seen from the code, both the methods, getHeight() and getBottom() are returning height as 0.
How to get the height (view end position) of both with respect to top of the cell display ?
Hope this helps
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
int parentHeight = MeasureSpec.getSize(heightMeasureSpec);
this.setMeasuredDimension(
parentWidth / 2, parentHeight);
}
This is how it can be done:
final TextView bottomTimeLine = (TextView) view.findViewById(R.id.textView1);
final int[] timelineCoord = new int[2];
final int[] imgCoord = new int[2];
ViewTreeObserver vto = bottomTimeLine.getViewTreeObserver();
vto.addOnGlobalLayoutListener((new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
bottomTimeLine.getLocationOnScreen(timelineCoord);
Log.d(" bottomTimeLine H ", ""+timelineCoord[1]);
timelineHeight = timelineCoord[1];
}
}));
ViewTreeObserver vt1 = img.getViewTreeObserver();
vt1.addOnGlobalLayoutListener((new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
img.getLocationOnScreen(imgCoord);
imgHeight = imgCoord[1] + img.getHeight();
Log.d("Img H ", ""+imgHeight);
if(imgHeight < timelineHeight)
{
int heightDiff = imgHeight - timelineHeight ;
heightDiff = heightDiff + 3;
img.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, heightDiff));
}
}
}));
I want to download an image (of unknown size, but which is always roughly square) and display it so that it fills the screen horizontally, and stretches vertically to maintain the aspect ratio of the image, on any screen size. Here is my (non-working) code. It stretches the image horizontally, but not vertically, so it is squashed...
ImageView mainImageView = new ImageView(context);
mainImageView.setImageBitmap(mainImage); //downloaded from server
mainImageView.setScaleType(ScaleType.FIT_XY);
//mainImageView.setAdjustViewBounds(true);
//with this line enabled, just scales image down
addView(mainImageView,new LinearLayout.LayoutParams(
LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
I accomplished this with a custom view. Set layout_width="fill_parent" and layout_height="wrap_content", and point it to the appropriate drawable:
public class Banner extends View {
private final Drawable logo;
public Banner(Context context) {
super(context);
logo = context.getResources().getDrawable(R.drawable.banner);
setBackgroundDrawable(logo);
}
public Banner(Context context, AttributeSet attrs) {
super(context, attrs);
logo = context.getResources().getDrawable(R.drawable.banner);
setBackgroundDrawable(logo);
}
public Banner(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
logo = context.getResources().getDrawable(R.drawable.banner);
setBackgroundDrawable(logo);
}
#Override protected void onMeasure(int widthMeasureSpec,
int heightMeasureSpec) {
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = width * logo.getIntrinsicHeight() / logo.getIntrinsicWidth();
setMeasuredDimension(width, height);
}
}
In the end, I generated the dimensions manually, which works great:
DisplayMetrics dm = new DisplayMetrics();
context.getWindowManager().getDefaultDisplay().getMetrics(dm);
int width = dm.widthPixels;
int height = width * mainImage.getHeight() / mainImage.getWidth(); //mainImage is the Bitmap I'm drawing
addView(mainImageView,new LinearLayout.LayoutParams(
width, height));
I just read the source code for ImageView and it is basically impossible without using the subclassing solutions in this thread. In ImageView.onMeasure we get to these lines:
// Get the max possible width given our constraints
widthSize = resolveAdjustedSize(w + pleft + pright, mMaxWidth, widthMeasureSpec);
// Get the max possible height given our constraints
heightSize = resolveAdjustedSize(h + ptop + pbottom, mMaxHeight, heightMeasureSpec);
Where h and w are the dimensions of the image, and p* is the padding.
And then:
private int resolveAdjustedSize(int desiredSize, int maxSize,
int measureSpec) {
...
switch (specMode) {
case MeasureSpec.UNSPECIFIED:
/* Parent says we can be as big as we want. Just don't be larger
than max size imposed on ourselves.
*/
result = Math.min(desiredSize, maxSize);
So if you have a layout_height="wrap_content" it will set widthSize = w + pleft + pright, or in other words, the maximum width is equal to the image width.
This means that unless you set an exact size, images are NEVER enlarged. I consider this to be a bug, but good luck getting Google to take notice or fix it. Edit: Eating my own words, I submitted a bug report and they say it has been fixed in a future release!
Another solution
Here is another subclassed workaround, but you should (in theory, I haven't really tested it much!) be able to use it anywhere you ImageView. To use it set layout_width="match_parent", and layout_height="wrap_content". It is quite a lot more general than the accepted solution too. E.g. you can do fit-to-height as well as fit-to-width.
import android.content.Context;
import android.util.AttributeSet;
import android.widget.ImageView;
// This works around the issue described here: http://stackoverflow.com/a/12675430/265521
public class StretchyImageView extends ImageView
{
public StretchyImageView(Context context)
{
super(context);
}
public StretchyImageView(Context context, AttributeSet attrs)
{
super(context, attrs);
}
public StretchyImageView(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
// Call super() so that resolveUri() is called.
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// If there's no drawable we can just use the result from super.
if (getDrawable() == null)
return;
final int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
final int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
int w = getDrawable().getIntrinsicWidth();
int h = getDrawable().getIntrinsicHeight();
if (w <= 0)
w = 1;
if (h <= 0)
h = 1;
// Desired aspect ratio of the view's contents (not including padding)
float desiredAspect = (float) w / (float) h;
// We are allowed to change the view's width
boolean resizeWidth = widthSpecMode != MeasureSpec.EXACTLY;
// We are allowed to change the view's height
boolean resizeHeight = heightSpecMode != MeasureSpec.EXACTLY;
int pleft = getPaddingLeft();
int pright = getPaddingRight();
int ptop = getPaddingTop();
int pbottom = getPaddingBottom();
// Get the sizes that ImageView decided on.
int widthSize = getMeasuredWidth();
int heightSize = getMeasuredHeight();
if (resizeWidth && !resizeHeight)
{
// Resize the width to the height, maintaining aspect ratio.
int newWidth = (int) (desiredAspect * (heightSize - ptop - pbottom)) + pleft + pright;
setMeasuredDimension(newWidth, heightSize);
}
else if (resizeHeight && !resizeWidth)
{
int newHeight = (int) ((widthSize - pleft - pright) / desiredAspect) + ptop + pbottom;
setMeasuredDimension(widthSize, newHeight);
}
}
}
Setting adjustViewBounds to true and using a LinearLayout view group worked very well for me. No need to subclass or ask for device metrics:
//NOTE: "this" is a subclass of LinearLayout
ImageView splashImageView = new ImageView(context);
splashImageView.setImageResource(R.drawable.splash);
splashImageView.setAdjustViewBounds(true);
addView(splashImageView);
I've been struggling with this problem in one form or another for AGES, thank you, Thank You, THANK YOU.... :)
I just wanted to point out that you can get a generalizable solution from what Bob Lee's done by just extending View and overriding onMeasure. That way you can use this with any drawable you want, and it won't break if there's no image:
public class CardImageView extends View {
public CardImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public CardImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CardImageView(Context context) {
super(context);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Drawable bg = getBackground();
if (bg != null) {
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = width * bg.getIntrinsicHeight() / bg.getIntrinsicWidth();
setMeasuredDimension(width,height);
}
else {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
}
In some cases this magic formula beautifully solves the problem.
For anyone struggling with this coming from another platform, the "size and shape to fit" option is handled beautifully in Android, but it's hard to find.
You typically want this combination:
width match parent,
height wrap content,
adjustViewBounds turned ON (sic)
scale fitCenter
cropToPadding OFF (sic)
Then it's automatic and amazing.
If you're an iOS dev, it's utterly amazing how simply, in Android, you can do "totally dynamic cell heights" in a table view .. err, I mean ListView. Enjoy.
<com.parse.ParseImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/post_image"
android:src="#drawable/icon_192"
android:layout_margin="0dp"
android:cropToPadding="false"
android:adjustViewBounds="true"
android:scaleType="fitCenter"
android:background="#eff2eb"/>
I have managed to achieve this using this XML code only. It might be the case that eclipse does not render the height to show it expanding to fit; however, when you actually run this on a device, it properly renders and provides the desired result. (well at least for me)
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:scaleType="centerCrop"
android:src="#drawable/whatever" />
</FrameLayout>
I did it with these values within a LinearLayout:
Scale type: fitStart
Layout gravity: fill_horizontal
Layout height: wrap_content
Layout weight: 1
Layout width: fill_parent
Everyone is doing this programmily so I thought this answer would fit perfectly here. This code worked for my in the xml. Im NOT thinking about ratio yet, but still wanted to place this answer if it would help anyone.
android:adjustViewBounds="true"
Cheers..
A very simple solution is to just use the features provided by RelativeLayout.
Here is the xml that makes it possible with standard Android Views:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
<LinearLayout
android:id="#+id/button_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_alignParentBottom="true"
>
<Button
android:text="button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button
android:text="button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button
android:text="button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
<ImageView
android:src="#drawable/cat"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:adjustViewBounds="true"
android:scaleType="centerCrop"
android:layout_above="#id/button_container"/>
</RelativeLayout>
</ScrollView>
The trick is that you set the ImageView to fill the screen but it has to be above the other layouts. This way you achieve everything you need.
Its simple matter of setting adjustViewBounds="true" and scaleType="fitCenter" in the XML file for the ImageView!
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:src="#drawable/image"
android:adjustViewBounds="true"
android:scaleType="fitCenter"
/>
Note: layout_width is set to match_parent
You are setting the ScaleType to ScaleType.FIT_XY. According to the javadocs, this will stretch the image to fit the whole area, changing the aspect ratio if necessary. That would explain the behavior you are seeing.
To get the behavior you want... FIT_CENTER, FIT_START, or FIT_END are close, but if the image is narrower than it is tall, it will not start to fill the width. You could look at how those are implemented though, and you should probably be able to figure out how to adjust it for your purpose.
ScaleType.CENTER_CROP will do what you want: stretch to full width, and scale the height accordingly. if the scaled height exceeds the screen limits, the image will be cropped.
Look there is a far easier solution to your problem:
ImageView imageView;
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.your_layout);
imageView =(ImageView)findViewById(R.id.your_imageView);
Bitmap imageBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.your_image);
Point screenSize = new Point();
getWindowManager().getDefaultDisplay().getSize(screenSize);
Bitmap temp = Bitmap.createBitmap(screenSize.x, screenSize.x, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(temp);
canvas.drawBitmap(imageBitmap,null, new Rect(0,0,screenSize.x,screenSize.x), null);
imageView.setImageBitmap(temp);
}
You can use my StretchableImageView preserving the aspect ratio (by width or by height) depending on width and height of drawable:
import android.content.Context;
import android.util.AttributeSet;
import android.widget.ImageView;
public class StretchableImageView extends ImageView{
public StretchableImageView(Context context) {
super(context);
}
public StretchableImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public StretchableImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if(getDrawable()!=null){
if(getDrawable().getIntrinsicWidth()>=getDrawable().getIntrinsicHeight()){
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = width * getDrawable().getIntrinsicHeight()
/ getDrawable().getIntrinsicWidth();
setMeasuredDimension(width, height);
}else{
int height = MeasureSpec.getSize(heightMeasureSpec);
int width = height * getDrawable().getIntrinsicWidth()
/ getDrawable().getIntrinsicHeight();
setMeasuredDimension(width, height);
}
}
}
}
For me the android:scaleType="centerCrop" did not resolve my problem. It actually expanded the image way more. So I tried with android:scaleType="fitXY" and It worked excellent.
This working fine as per my requirement
<ImageView
android:id="#+id/imgIssue"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:scaleType="fitXY"/>