I'm trying to implement Flexible Space with image pattern, using this tutorial.
Everything works fine.
Notice the height definition of the AppBarLayout which is 192dp.
I'd like to make the height 1/3 of the screen instead, to match this google example for the pattern here.
Here's the code in the activity's onCreate (the layout xml is exactly the same as in the tutorial):
AppBarLayout appbar = (AppBarLayout)findViewById(R.id.appbar);
float density = getResources().getDisplayMetrics().density;
float heightDp = getResources().getDisplayMetrics().heightPixels / density;
appbar.setLayoutParams(new CoordinatorLayout.LayoutParams(LayoutParams.MATCH_PARENT, Math.round(heightDp / 3)));
But for some reason, the result is not what I'm expecting. I can't see the app bar at all with this code. (without the code, the height shows as expected but it's from XML and can't be set dynamically).
Do this instead:
AppBarLayout appbar = (AppBarLayout) findViewById(R.id.appbar);
float heightDp = getResources().getDisplayMetrics().heightPixels / 3;
CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams)appbar.getLayoutParams();
lp.height = (int)heightDp;
In your original code I think that you calculation for 1/3 of the screen was wrong, but you still should have seen something. It could be that the LayoutParams.MATCH_PARENT in the setLP() wasn't imported correctly. Always declare the view type first, i.e. CoordinatorLayout.LayoutParams just to make sure. Otherwise it can be easy to use a Framelayout.LayoutParams, for instance.
Some methods for changing the AppBarLayout height programatically with dividing, percent or by weight of the screen height:
private AppBarLayout appbar;
/**
* #return AppBarLayout
*/
#Nullable
protected AppBarLayout getAppBar() {
if (appbar == null) appbar = (AppBarLayout) findViewById(R.id.appbar);
return appbar;
}
/**
* #param divide Set AppBar height to screen height divided by 2->5
*/
protected void setAppBarLayoutHeightOfScreenDivide(#IntRange(from = 2, to = 5) int divide) {
setAppBarLayoutHeightOfScreenPercent(100 / divide);
}
/**
* #param percent Set AppBar height to 20->50% of screen height
*/
protected void setAppBarLayoutHeightOfScreenPercent(#IntRange(from = 20, to = 50) int percent) {
setAppBarLayoutHeightOfScreenWeight(percent / 100F);
}
/**
* #param weight Set AppBar height to 0.2->0.5 weight of screen height
*/
protected void setAppBarLayoutHeightOfScreenWeight(#FloatRange(from = 0.2F, to = 0.5F) float weight) {
if (getAppBar() != null) {
ViewGroup.LayoutParams params = getAppBar().getLayoutParams();
params.height = Math.round(getResources().getDisplayMetrics().heightPixels * weight);
getAppBar().setLayoutParams(params);
}
}
If you want to follow the material design guidelines the height should be equal to the default height plus content increment(s)
https://www.google.com/design/spec/layout/structure.html#structure-app-bar
Related
I have an image saved in my database that is passed to an image as a byte array and then loaded to the Image view. However, I can't get it to fill the imageView. I use the following code:
package com.example.AppPrototipo.ui.tourist;
imports...
#Component
public class ExperienceController {
#FXML
Pane imagePane;
#FXML
ImageView imageViewPrincipal;
private final ExperienceRepository experienceRepository;
public ExperienceController(ExperienceRepository experienceRepository) {
this.experienceRepository = experienceRepository;
}
#FXML
private void initialize(){
Experience experience = experienceRepository.findById(1);
Image image = new Image(new ByteArrayInputStream(experience.getImages().get(0).getImageData()));
imageViewPrincipal.setImage(image);
imageViewPrincipal.fitWidthProperty().bind(imagePane.widthProperty());
imageViewPrincipal.fitHeightProperty().bind(imagePane.heightProperty());
}
}
This is the result i get:
The desired result would be that the image fills the whole width (fill the black side) by cropping the top and bottom sides and remaining centered. Would anyone be able to help me?
Assuming you're setting the preserveRatio property to true on the ImageView, and as matt stated is his comment, you only need to set one of them, say fitWidth, and the fitHeight will be calculated using the image ratio.
the problem is that the ratios of the image and the pane don't match so you need to do some cropping using setViewport, and it would be best to do the cropping when the pane's height or width change.
What you need to do is to calculate the ratio of the image, and compare it to the ratio of the pane, the comparison will let you decide whether to keep the original width or original height of the image, and you'll calculate the other using the pane's ratio.
Not really sure if that's the best practice but here's the code for what i have described
double oldImageWidth = image.getWidth(), oldImageHeight = image.getHeight(); //saving the original image size and ratio
double imageRatio = oldImageWidth / oldImageHeight;
imageViewPrincipal.setImage(image);
ChangeListener<Number> listener = (obs, ov, nv) -> {
double paneWidth = imagePane.getWidth();
double paneHeight = imagePane.getHeight();
double paneRatio = paneWidth / paneHeight; //calculating the new pane's ratio
//after width or height changed
double newImageWidth = oldImageWidth, newImageHeight = oldImageHeight;
if (paneRatio > imageRatio) {
newImageHeight = oldImageWidth / paneRatio;
} else if (paneRatio < imageRatio) {
newImageWidth = oldImageHeight * paneRatio;
}
imageViewPrincipal.setViewport(new Rectangle2D( // The rectangle used to crop
(oldImageWidth - newImageWidth) / 2, (oldImageHeight - newImageHeight) / 2, //MinX and MinY to crop from the center
newImageWidth, newImageHeight) // new width and height
);
imageViewPrincipal.setFitWidth(paneWidth);
};
imagePane.widthProperty().addListener(listener);
imagePane.heightProperty().addListener(listener);
And here is how it looks
My AppBarLayout hold a Toolbar and TabLayout. When view is anchored, height is set to 0 setLayoutParams(0). On another state, the view is collapsed, I need to restore appbar height. I tried setLayoutParams(heightDp) where
float heightDp = getResources().getDisplayMetrics().heightPixels / 6;
but the height is not accurate.
private void setLayoutParams(int paramsHeight) {
CoordinatorLayout.LayoutParams lsp = (CoordinatorLayout.LayoutParams) mAppBarLayout.getLayoutParams();
lsp.height = paramsHeight;
mAppBarLayout.setLayoutParams(lsp);
}
How can I determine exact AppBar height programatically.
You should get it from default resources with TypedArray:
int mActionBarSize;
TypedArray attrs= getContext().getTheme().obtainStyledAttributes(new int[] { android.R.attr.actionBarSize });
mActionBarSize = (int) attrs.getDimension(0, 0);
You must recycle TypedArray
attrs.recycle();
This way you will get the value according to your screen.
I have a set of ImageViews whose BackgroundResource and LayoutParams will be defined in a separate xml file. The height, width, marginleft and margintop are given in pixels. The values are in respect to a 1024x600 pixel resolution screen. The code i'm using
ImageView ImgV= (ImageView)findViewById(R.id.ImgV_1);
RelativeLayout.LayoutParams the_dimens = new RelativeLayout.LayoutParams(50,50);
the_dimens.setMargins(800,50,0,0);
ImgV.setBackgroundResource(R.drawable.bulbon);
ImgV.setLayoutParams(the_dimens);
While the height and width seem to be rightly displayed in pixels, the margins are not. So how can I set the margin values to apply in pixels rather than whatever default units the below code takes.
the_dimens.setMargins(800,50,0,0);
The app is only for a 1024x600 device, so i'm not worried about resolution independent design.
Thanks.
check this
int dpValue = 5; // margin in dips
float d = context.getResources().getDisplayMetrics().density;
int margin = (int)(dpValue * d); // margin in pixels
You can do in this way:
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
lp.setMargins(left, top, right, bottom);
imageView.setLayoutParams(lp);
this is my first post. I am learning to code in java for android apps.
I am using a LinearLayout "variable named: ll" with a predefined layout_weight (which I want to change whenever I want in the future) and height and width set to MATCH_PARENT. I want to get the height of this LinearLayout in pixels. I fill this using java (ll.addView(variableForAnObject);).
I am trying to get its height using ll.getLayoutParams().height; but I am getting -1. Because I believe this is the constant for MATCH_PARENT. Setting the height to 0dp makes the ll invisible and gives height as 0.
Please tell me if there's a way to get its height. I think I can do this by getting screen height using DisplayMetrics and making nearly impossible calculations (for me, at least) but this will be too complex.
try with ll.getHeight() should work
if not, it's because android has not yet calculed its bounds, then:
//inside of onCreate method should work
ll.post(new Runnable() {
#Override
public void run() {
//maybe also works height = ll.getLayoutParams().height;
height = ll.getHeight();
}
});
It is -1 because its dimensions have not yet been set, whenever you set layout it takes some time to compute the actual values including height, width etc.
Use OnLayoutListener to listen when it has finished with the layout.
layout.onLayoutChange (View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
//Extract values here
height = view.getHeight();
width = view.getWidth()
}
See this for more about the OnLayoutListener
Define your LinearLayout in your class and use getHeight() and getWidth(). Example:
LinearLayout yourLayout = (LinearLayout) findViewById (R.id.yourLL);
double height = yourLayout.getHeight();
double width = yourLayout.getWidth();
Hope it helps! :)
Give the id field in your layout xml file:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:id="#+id/<ID>>
Use this id to get reference in java class and find height and width:
LinearLayout linearLayout= (LinearLayout) findViewById (R.id.<ID>);
double height = linearLayout.getHeight();
double width = linearLayout.getWidth();
I'm having trouble trying to set a specific size for the width of my custom view. I know I can just hard-code a value in the layout_width field in the XML file but I'm trying not to result to hard-coding values. I need my View to be half the size of the screen. So, within the class I find half the screen size:
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
try{
Point size = new Point();
display.getSize(size);
screenWidth = size.x;
}catch(NoSuchMethodError e){
screenWidth = display.getWidth();
}
Then, I call:
measure(width|MeasureSpec.EXACTLY, LayoutParams.WRAP_CONTENT|MeasureSpec.EXACTLY);
//Where width is equal to half the screen width
but this does not seem to be working for my case. So, to sum it all up, how do you properly specify a particular size for a custom View? Any help will be useful and appreciated! Thanks!
Override the onMeasure() method in your Custom View:
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = getResources().getDisplayMetrics().widthPixels >> 1;
widthMeasureSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
Basically, override the width MeasureSpec to be exactly half the width of the screen, then pass that through to the superclass.
I believe that you might not be able to accurately get the width of the screen at this point because you need to wait till the entire hierarchy (up until the most root view) is laid out. You may need to do something like:
ViewTreeObserver.OnGlobalLayoutListener layoutListener = new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
int width = getWidth();
int height = getHeight();
//set layoutparams with those values.
}
};
getViewTreeObserver().addOnGlobalLayoutListener(layoutListener);
You can confirm the correctness of this by seeing if the values you're getting when you try getting the display width inside of onMeasure differ from the values you get when the onGlobalLayout callback is invoked.