I am coding a custom view, extended from RelativeLayout, and I want to resize it programmatically, How can I do?
the custom view Class is something like:
public ActiveSlideView(Context context, AttributeSet attr){
super(context, attr);
LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if(inflater != null){
inflater.inflate(R.layout.active_slide, this);
}
Android throws an exception if you fail to pass the height or width of a view.
Instead of creating a new LayoutParams object, use the original one, so that all other set parameters are kept. Note that the type of LayoutParams returned by getLayoutParams is that of the parent layout, not the view you are resizing.
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) someLayout.getLayoutParams();
params.height = 130;
someLayout.setLayoutParams(params);
this.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, theSizeIWant));
Problem solved!
NOTE: Be sure to use the parent Layout's LayoutParams. Mine is LinearLayout.LayoutParams!
This works for me:
ViewGroup.LayoutParams params = layout.getLayoutParams();
params.height = customHeight;
layout.requestLayout();
In Kotlin, you can use the ktx extensions:
yourView.updateLayoutParams {
height = <YOUR_HEIGHT>
}
For what it's worth, let's say you wanted to resize the view in device independent pixels (dp): -
You need to use a method called applyDimension, that's a member of the class TypedValue to convert from dp to pixels. So if I want to set the height to 150dp (say) - then I could do this:
float pixels = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 150, getResources().getDisplayMetrics());
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) someLayout.getLayoutParams();
params.height = (int) pixels;
someLayout.setLayoutParams(params);
where the expression: getResources().getDisplayMetrics() gets the screen density/resolution
Here's a more generic version of the solution above from #herbertD :
private void resizeView(View view, int newWidth, int newHeight) {
try {
Constructor<? extends LayoutParams> ctor = view.getLayoutParams().getClass().getDeclaredConstructor(int.class, int.class);
view.setLayoutParams(ctor.newInstance(newWidth, newHeight));
} catch (Exception e) {
e.printStackTrace();
}
}
try a this one:
...
View view = inflater.inflate(R.layout.active_slide, this);
view.setMinimumWidth(200);
I used this way to increase width of custom view
customDrawingView.post(new Runnable() {
#Override
public void run() {
View view_instance = customDrawingView;
android.view.ViewGroup.LayoutParams params = view_instance
.getLayoutParams();
int newLayoutWidth = customDrawingView
.getWidth()
+ customDrawingView.getWidth();
params.width = newLayoutWidth;
view_instance.setLayoutParams(params);
screenWidthBackup = params.width;
}
});
With Kotlin and using dp unit:
myView.updateLayoutParams {
val pixels = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 200f, context.resources.displayMetrics)
height = pixels.toInt()
}
I solved it this way.. I have basically a simple view inside xml file.
View viewname = findViewById(R.id.prod_extra);
prodExtra.getLayoutParams().height=64;
If you have only two or three condition(sizes) then you can use #Overide onMeasure like
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
And change your size for these conditions in CustomView class easily.
This is how it can be done in Kotlin:
updateLayoutParams:
val view = layoutInflater.inflate(R.layout.cell, binding.ssss, false).apply {
id = View.generateViewId()
updateLayoutParams {
height = 200
width = 400
}
}
binding.ssss.addView(view)
OR
layoutParams:
val view = layoutInflater.inflate(R.layout.cell, binding.ssss, false).apply {
id = View.generateViewId()
layoutParams.width = 200
layoutParams.height = 200
}
binding.ssss.addView(view)
if you are overriding onMeasure, don't forget to update the new sizes
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(newWidth, newHeight);
}
This is how I achieved this. In Sileria answer he/she did the following:
ViewGroup.LayoutParams params = layout.getLayoutParams();
params.height = customHeight;
layout.requestLayout();
This is correct, but it expects us to give the height in pixels, but I wanted to give the dp I want the height to be so I added:
public int convertDpToPixelInt(float dp, Context context) {
return (int) (dp * (((float) context.getResources().getDisplayMetrics().densityDpi) / 160.0f));
}
So it will look like this:
ViewGroup.LayoutParams params = layout.getLayoutParams();
params.height = convertDpToPixelInt(50, getContext());
layout.requestLayout();
This is what I did:
View myView;
myView.getLayoutParams().height = 32;
myView.getLayoutParams().width = 32;
If there is a view group that this view belongs to, you may also need to call yourViewGroup.requestLayout() for it to take effect.
fun View.setSize(width: Int, height: Int) {
updateLayoutParams {
this.width = width
this.height = height
}
}
Related
I tried setting height/width manually in button but it didn't work. Then implemented Layoutparams. But size shows small and not getting required dp value.
XML
<Button
android:id="#+id/itemButton"
android:layout_width="88dp"
android:layout_height="88dp"
android:layout_marginRight="5dp"
android:layout_marginBottom="5dp"
android:background="#5e5789"
android:gravity="bottom"
android:padding="10dp"
android:text=""
android:textColor="#FFF"
android:textSize="10sp" />
Constructor:
public Item (int id, String name, String backgroundColor, String textColor, int width, int height){
this.id = id;
this.name = name;
this.backgroundColor = backgroundColor;
this.textColor = textColor;
this.width = width;
this.height = height;
}
Adapter:
#Override public void onBindViewHolder(final ViewHolder holder, int position) {
final Item item = items.get(position);
holder.itemView.setTag(item);
holder.itemButton.setText(item.getName());
holder.itemButton.setTextColor(Color.parseColor(item.getTextColor()));
holder.itemButton.setBackgroundColor(Color.parseColor(item.getBackgroundColor()));
ViewGroup.LayoutParams params = holder.itemButton.getLayoutParams();
params.width = item.getWidth();
params.height = item.getHeight();
holder.itemButton.setLayoutParams(params);
}
When you specify values programmatically in the LayoutParams, those values are expected to be pixels.
To convert between pixels and dp you have to multiply by the current density factor. That value is in the DisplayMetrics, that you can access from a Context:
float pixels = dp * context.getResources().getDisplayMetrics().density;
So in your case you could do:
.
.
float factor = holder.itemView.getContext().getResources().getDisplayMetrics().density;
params.width = (int)(item.getWidth() * factor);
params.height = (int)(item.getHeight() * factor);
.
.
I believe you should be using a dp value defined in dimens along with getDimensionPixelSize. In a custom view, the Kotlin implementation would look like:
val layoutParams = layoutParams
val width = context.resources.getDimensionPixelSize(R.dimen.width_in_dp)
layoutParams.width = width
Option 1: Use dimens.xml
view.updateLayoutParams {
width = resources.getDimensionPixelSize(R.dimen.my_width)
height = resources.getDimensionPixelSize(R.dimen.my_height)
}
Option 2: Dispense with dimens.xml
/** Converts dp to pixel. */
val Int.px get() = (this * Resources.getSystem().displayMetrics.density).toInt()
view.updateLayoutParams {
width = 100.px
height = 100.px
}
ViewGroup.LayoutParams params = ListView.getLayoutParams();
params.height = (int) (50 * customsDebts.size() * (getResources().getDisplayMetrics().density));
params.width = ViewGroup.LayoutParams.MATCH_PARENT;
ListView.setLayoutParams(params);
I am trying to set the layout width programatically .
ViewTreeObserver vtoRecyclerView = mMainLayout.getViewTreeObserver();
vtoRecyclerView.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
mMainLayout.getViewTreeObserver().removeGlobalOnLayoutListener(this);
ViewGroup.LayoutParams lpView = mMainLayout.getLayoutParams();
lpView.width = ViewGroup.LayoutParams.MATCH_PARENT-20;
mMainLayout.requestLayout();
}
});
but mMainLayout.getLayoutParams() is returning width as -1 .so when I set width as match_parent - 20 it becomes -21. I want to set the width as match_parent - 20.
What is wrong with the approach.
The root problem with your code here, is because you set the width with:
lpView.width = ViewGroup.LayoutParams.MATCH_PARENT-20;
while ViewGroup.LayoutParams.MATCH_PARENT is a constant.
You can find the constant on ViewGroup class
public static final int MATCH_PARENT = -1;
So that is obvious, because -1 - 20 is -21
What you can do here is, you can change the line to
lpView.width = mMainLayout.getWidth()-20;
try this.
DisplayMetrics displaymetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
int height = displaymetrics.heightPixels;
int width = displaymetrics.widthPixels;
ViewTreeObserver vtoRecyclerView = mMainLayout.getViewTreeObserver();
vtoRecyclerView.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
mMainLayout.getViewTreeObserver().removeGlobalOnLayoutListener(this);
ViewGroup.LayoutParams lpView = mMainLayout.getLayoutParams();
lpView.width = width -20;
mMainLayout.requestLayout();
}
});
Try this.
ViewTreeObserver vtoRecyclerView = mMainLayout.getViewTreeObserver();
vtoRecyclerView.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
if(mMainLayout.getWidth > 10 && mMainLayout.getHeight() > 10) // you can modify this value.
{
mMainLayout.getViewTreeObserver().removeGlobalOnLayoutListener(this);
ViewGroup.LayoutParams lpView = mMainLayout.getLayoutParams();
lpView.width = ViewGroup.LayoutParams.MATCH_PARENT-20; // This seems to be wrong;
ViewParent parent = mMainLayout.getParent();
if(parent != null) {
lpView.width = (View)parent.getWidth();
}
mMainLayout.requestLayout();
}
}
});
I had the same problem while setting width as match_parent, I had resolved this by getting the phone screen width as follows:
Display display = ((Activity) context).getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int width = size.x;
int ActualWidth=width-(`margin you set for view`);
Hope it will help :)
As ViewGroup.LayoutParams.MATCH_PARENT constant predefined numeric value is -1 so you are getting -21 as result. and what you want can be achieved by defining margin to a layout rather than using that approach.
My code for fixing ImageView:
private void fixImageWidth() {
int parentHeight = getHeight();
if (parentHeight == 0 || getParent() == null)
return;
Drawable drawable = image.getDrawable();
LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) image.getLayoutParams();
if (drawable != null) {
int height = drawable.getIntrinsicHeight();
int width = drawable.getIntrinsicWidth();
lp.width = (int) ((float)(parentHeight - lp.topMargin * 2) / height * width);
} else {
lp.width = LayoutParams.WRAP_CONTENT;
}
image.requestLayout();
}
But sometimes actually image bounds is not changed. Below you could see HierarchyViewer properties of that object:
EDIT:
After I lot for debugging I determined, sometimes requestLayout don't remeasure image view. How does this happens?
EDIT:
I found solution, but still don't know reason. Solution is below:
image.post(new Runnable() {
#Override
public void run() {
image.requestLayout();
}
});
Any ideas?
Because getWidth() and getLayoutParams().width are different things. 1st relates to the View, the second is a layout request to the parent. If the parent cannot match the request the View maybe laid out with a different width. In this case you have requested MATCH_PARENT in the layout height and since an ImageView has a default scaleType of FIT_CENTER therefore content aspect ratio is maintained so the width will change.
I have created an array of buttons. Now I want to find the height and width of the button, and for that, I have used getWidth() and getHeight(). But the thing is that it always returns 0. Why is this happening? I have send my code, please check if anything is wrong.
LinearLayout layoutVertical = (LinearLayout) findViewById(R.id.liVLayout);
LinearLayout rowLayout = null;
LayoutParams param = new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT, 1);
public static void main(String[] args)
{
DBFacade dbFacade = new DBFacade();
dbFacade.pick();
}
//Create Button
for(int i=0;i<6;i++)
{
rowLayout=new LinearLayout(this);
rowLayout.setWeightSum(7);
layoutVertical.addView(rowLayout,param);
for(int j=0;j<7;j++)
{
m_pBtnDay[i][j]=new Button(this);
rowLayout.addView(m_pBtnDay[i][j],param);
m_pBtnDay[i][j].setOnLongClickListener(this);
m_pBtnDay[i][j].setGravity(Gravity.CENTER_HORIZONTAL|Gravity.CENTER_VERTICAL);
m_pBtnDay[i][j].setTextSize(12);
}
}
x=m_pBtnDay[i][j].getWidth();
y=m_pBtnDay[i][j].getHeight();
Log.d("width",Integer.toString(x));
Log.d("Height",Integer.toString(y));
return true;
Probably you are calling getWidth() and getHeight() too early: I think the UI has not been sized and laid out on the screen yet...
You can try to put that code inside this:
#Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
// Call here getWidth() and getHeight()
}
Another way
ViewTreeObserver vto = button.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
width = button.getWidth();
height = button.getHeight();
}
});
put this in your loop
x = m_pBtnDay[i][j].getWidth();
y = m_pBtnDay[i][j].getHeight();
Log.d("width", Integer.toString(x));
Log.d("Height", Integer.toString(y));
try it
You try to use the count-variable "i" and "j" to use outside from both for-loops. That should raise an exception because the are only availabil in each for-block.
Try to make the output in the second for-loop...
for (int i = 0; i<6; i++)
{
...
for(int j=0; j<7; j++)
{
....
x = m_pBtnDay[i][j].getWidth();
y = m_pBtnDay[i][j].getHeight();
Log.d("width", Integer.toString(x));
Log.d("Height", Integer.toString(y));
}
}
You can override the following View method, called during the layout phase.
protected void onSizeChanged (int w, int h, int oldw, int oldh)
This seems more appropriate, as it expressly accounts for the zero width and height you're observing:
This is called during layout when the size of this view has changed.
If you were just added to the view hierarchy, you're called with the
old values of 0.
Parameters w Current width of this view. h Current height of this
view. oldw Old width of this view. oldh Old height of this view.
See here.
Try this can also work:
btn.getDrawingCache().getHeight() and btn.getDrawingCache().getWidth()
I want to save(export) contents of MyView, which extends TextView, into a bitmap.
I followed the code: [this][1].
It works fine when the size of the text is small.
But when there are lots of texts, and some of the content is out of the screen, what I got is only what showed in the screen.
Then I add a "layout" in my code:
private class MyView extends TextView{
public MyView(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
public Bitmap export(){
Layout l = getLayout();
int width = l.getWidth() + getPaddingLeft() + getPaddingRight();
int height = l.getHeight() + getPaddingTop() + getPaddingBottom();
Bitmap viewBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(viewBitmap);
setCursorVisible(false);
layout(0, 0, width, height);
draw(canvas);
setCursorVisible(true);
return viewBitmap;
}
}
Now the strange thing happened:
The first time I invoke "export"(I use an option key to do that), I got contents only on the screen.
When I invoke "export" again, I got complete contents, including those out of the screen.
Why?
How to "export" a view, including contents cannot be showed on the screen?
Thank you!
[1]: http://www.techjini.com/blog/2010/02/10/quicktip-how-to-convert-a-view-to-an-image-android/ this
I found out a simpler way:
Put the TextView in a ScrollView.
Now myTextView.draw(canvas) will draw all of the text.
I think you should be subtracting the padding from the width in the height instead of adding it. Adding it will give you an area larger than the screen.
I solved this issue this way(strange but works):
public Bitmap export(){
//...
LayoutParams lp = getLayoutParams();
int old_width = lp.width;
int old_height = lp.height;
int old_scroll_x = getScrollX();
int old_scroll_y = getScrollY();
lp.width = width;
lp.height = height;
layout(0, 0, width, height);
scrollTo(0, 0);
draw(canvas);
lp.width = old_width;
lp.height = old_height;
setLayoutParams(lp);
scrollTo(old_scroll_x, old_scroll_y);
//...
}