I have simply extended the ImageView so an image goes full width. Like so:..
public class BannerImageView extends ImageView {
public BannerImageView(Context context) {
super(context);
}
public BannerImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public BannerImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = width * getDrawable().getIntrinsicHeight() / getDrawable().getIntrinsicWidth();
setMeasuredDimension(width, height);
}
}
In XML I have declared it as follows:
<com.whatever.next.BannerImageView
android:id="#+id/banner"
android:src="#+drawable/logo"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
I receive the following errors:
main.xml: Unable to resolve drawable "com.android.layoutlib.bridge.ResourceValue#48537a0f" in attribute "src"
then I get the expected null pointer exceptions.
I am confused as I thought since I am not altering the default behaviour of the ImageView it would show in the graphical layout. I have read through the other similar questions and that confused me some more.
For the record the above code works fine on an actual device.
Any help is appreciated!
instead of
android:src="#+drawable/logo"
use
android:src="#drawable/logo"
No + for the src attribute
Related
Hi I want to set android custom buttons' setMinHeight and setMaxHeight
I have android button widget in the Library project and user of SDK(library project) can take use of that custom Button but I want to put restriction that button's Minimum size has to be 200dp and button's maximum height can not exceed 350dp how do i achieve that from custom view Button custom class?
Tried searching lot of thread but not sure yet.
public class MyCustomButton extends android.widget.Button {
public MyCustomButton(Context context) {
super(context);
applyDefaults(null);
}
public MyCustomButton(Context context, AttributeSet attrs) {
super(context, attrs);
applyDefaults(attrs);
}
public MyCustomButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
applyDefaults(attrs);
}
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
public MyCustomButton(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
applyDefaults(attrs);
}
private void applyDefaults(AttributeSet attrs) {
String height = attrs.getAttributeValue("http://schemas.android.com/apk/res/android", "layout_height");
String width = attrs.getAttributeValue("http://schemas.android.com/apk/res/android", "layout_width");
Log.e("MVYAS=======", "height===" + height);
Log.e("MVYAS=======", "width===" + width);
setUpButtonForLoginOrLogout();
setAllCaps(false);
setMinHeight(getResources().getDimensionPixelSize(R.dimen.mid_button_min_height));
setMinWidth(getResources().getDimensionPixelSize(R.dimen.mid_button_min_width));
setMaxHeight(getResources().getDimensionPixelSize(R.dimen.mid_button_max_height));
setMaxWidth(getResources().getDimensionPixelSize(R.dimen.mid_button_max_width));
}
}
and while using into layout.xml file
<com.example.library.widget.MyCustomButton
android:id="#+id/my_button"
android:layout_width="153dp"
android:layout_height="57dp"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_alignWithParentIfMissing="true"
android:layout_margin="10dp"
styleButton:mobileid="inverted"/>
Here user should not be able to create button height to 57dp as its lower than the desired button height.
Putting restriction by adding setMinHeight() and setMaxHeight() dose not work.
How do i achieve that. Your help appreciated.
Thanks in Advance.
Just add these below two methods in MyCustomButtom class and try it:
#Override
public void setMinimumHeight(int minHeight) {
super.setMinimumHeight(minHeight);
}
#Override
public void setMinHeight(#Px int minHeight) {
super.setMinHeight(minHeight);
}
And one more thing, add below line in applyDefaults() function.
setMinimumHeight(getResources().getDimensionPixelSize(R.dimen.mid_button_min_height));
I have an 32x32 image in an ImageButton. Although layout_width and layout_height are set to wrap_content the ImageButton is shown as a rectangle with the height greater than the width. The container layout is a LinearLayout, nothing special around weighting the size of other widgets in this layout.
Why is this? It seems after I have upgraded my phone from 4.1.1. to 4.4 this strange behavior came in.
Is the image fixed size. If yes means you can mention the fixed size instead of using wrap content.
Or if it's dynamic means you can use the below SquareImageview
public class SquareImageView extends ImageView {
public SquareImageView(Context context) {
super(context);
}
public SquareImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SquareImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = getMeasuredWidth();
setMeasuredDimension(width, width);
}
}
Use this class in your app.
Then call this SquareImageView instead of ImageView and the layout_height should be match_parent
I am trying to create ViewGroup based on FrameLayout that might be rotated 90 degrees CW / CCW and it still will be working correctly
So far my results are not so sucesful. So far it looks like that ( left side before rotation, right after; sorry for bright red )
Layout for Activity
<?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">
<com.example.TestProject.RotatedFrameLayout
android:id="#+id/container"
android:layout_centerInParent="true"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#00F"/>
</RelativeLayout>
RotatedFrameLayout
public class RotatedFrameLayout extends FrameLayout {
private boolean firstMeasure = true;
public RotatedFrameLayout( Context context ) {
super( context );
init();
}
public RotatedFrameLayout( Context context, AttributeSet attrs ) {
super( context, attrs );
init();
}
public RotatedFrameLayout( Context context, AttributeSet attrs, int defStyle ) {
super( context, attrs, defStyle );
init();
}
private void init() {
setRotation( 90f );
}
#Override
protected void onMeasure( int widthMeasureSpec, int heightMeasureSpec ) {
super.onMeasure( heightMeasureSpec, widthMeasureSpec );
}
}
Some extra info
I don't want to use Animation rotation because buttons aren't clickable that way
I don't want to use landscape mode because in landscape on screen navigation buttons took a lot of space on Nexus 7 ( this is the main reason why I am trying to greate that rotated
It seems that only left and right side of the screen are out of bounds
It is quite hard to do and I think it is not worth doing. But if you really want to do this you need:
pass to ViewGroup correct size dimentions (swap width and height).
rotate ViewGroup canvas 90 degrees.
At this point everything should look fine, but touch events not working properly.
intercept all touch events and swap x and y. Then pass fixed events to ViewGroup.
I dont have any code samples and have never seen any ) This way should work, we did scale transformations with fragments where we had to fix touch events coordinates when fragment was scaled.
I havent tested it heavily but this works:
public class RotatedFrameLayout extends FrameLayout {
public RotatedFrameLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
public RotatedFrameLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public RotatedFrameLayout(Context context) {
super(context);
init();
}
#SuppressLint("NewApi")
private void init() {
setPivotX(0);
setPivotY(0);
setRotation(90f);
}
#SuppressLint("NewApi")
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(heightMeasureSpec, widthMeasureSpec);
setTranslationX(getMeasuredHeight());
}
}
I am trying to reduce the line spacing in a TextView by setting a negative 'add' to TextView.setLineSpacing(). It works well except that the bottom line get truncated.
Main layout
<TextView
android:id="#+id/text_view"
android:padding="dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
tools:context=".MainActivity" />
Main activity: (notice the
package com.font_test;
import android.app.Activity;
import android.graphics.Typeface;
import android.os.Bundle;
import android.widget.TextView;
public class MainActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final Typeface typeface = Typeface.createFromAsset(getAssets(), "fonts/custom_fonts.ttf");
final TextView tv = (TextView) findViewById(R.id.text_view);
tv.setTypeface(typeface);
tv.setTextSize(60);
tv.setLineSpacing(-30f, 1f); // *** -30 to reduce line spacing
tv.setBackgroundColor(0x280000ff);
tv.setText("gggkiiikkk" + "\n" + "gikgikgik" + "\n" + "kigkigkig");
}
}
This results in truncation at the bottom of the view (notice the 'g' at the bottom line):
It seems that the problem is related to incorrect layout measurement. If I set the TextView to
android:layout_height="fill_parent"
It does render properly:
Any idea how to fix it? I don't mind to have ugly workarounds if it helps. I also have access to FontForge and I can modify the font file if needed.
littleFluffyKittys answer is good but it didn't work on some devices if the linespacing was set through xml
I calculate the additional height needed by comparing the original height of the font with the height the textview calculates for a line.
If the line height is smaller than the height of the font the diffrence is added one time.
This works down to at least API 10 propably lower (just not tested any lower)
public class ReducedLineSpacingTextView extends TextView {
public ReducedLineSpacingTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public ReducedLineSpacingTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ReducedLineSpacingTextView(Context context) {
super(context);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int truncatedHeight = getPaint().getFontMetricsInt(null) - getLineHeight();
if (truncatedHeight > 0) {
setMeasuredDimension(getMeasuredWidth(), getMeasuredHeight() + truncatedHeight);
}
}
}
I ran into this same problem but when I was trying to use a spacing multiplier less than 1.
I created a subclass of TextView that fixes the truncation of the last line automatically and doesn't require you set a known/fixed spacing at the bottom.
Just use this class and you can use it normally, you don't need to apply any additional spacing or fixes.
public class ReducedLineSpacingTextView extends TextView {
private boolean mNegativeLineSpacing = false;
public ReducedLineSpacingTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public ReducedLineSpacingTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ReducedLineSpacingTextView(Context context) {
super(context);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (mNegativeLineSpacing) { // If you are only supporting Api Level 16 and up, you could use the getLineSpacingExtra() and getLineSpacingMultiplier() methods here to check for a less than 1 spacing instead.
Layout layout = getLayout();
int truncatedHeight = layout.getLineDescent(layout.getLineCount()-1);
setMeasuredDimension(getMeasuredWidth(), getMeasuredHeight() + truncatedHeight);
}
}
#Override
public void setLineSpacing(float add, float mult) {
mNegativeLineSpacing = add < 0 || mult < 1;
super.setLineSpacing(add, mult);
}
}
Nice!
That'll make the job but it's never a good idea to put constants values wherever we have variables. You can use the lineSpacing values to add them to the onMeasure method in a dinamyc way.
Note that this values are always available through "getLineSpacingExtra()" and "getLineSpacingMultiplier()". Or even easier you can get the value of both summed up: "getLineHeight()".
Although it feels for me that this value should be included in the onMeasure method, you can always measure the exact height you need and then make a simple check:
final int measuredHeight = getMeasuredHeight();
if (measuredHeight < neededHeight) {
setMeasuredDimension(getMeasuredWidth, neededHeight);
}
One last thing, you don't need to pass the context along in a separated attribute. If you have a look to your constructors, the context is already there. If you needed along the code of your component you can just use "getContext()".
Hope it helps.
Use this to reduce line spacing in text view
**
android:lineSpacingMultiplier="0.8"
**
If padding doesn't work, margin should do the job. If you still have problem you can always apply the line spacing value to the onMeasure method of the view. You'll have to create a custom component for that and extend onMeasure.
Just add paddingBottom to declaration of your TextView xml, pick a value which produces a good result. And consequently set values for other paddings (top, let and right). This should fix your problem
This is what I did based on Jose's answer here and it seems to work. I am not very familiar with the intricate of the layout mechanism. Is this code safe? Any problem with it?
Layout:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<com.font_test.MyTextView
android:id="#+id/text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
tools:context=".MainActivity" />
</RelativeLayout>
Added custom TextView that extends the vertical height by N pixels:
package com.font_test;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.TextView;
public class MyTextView extends TextView {
public MyTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// TODO: provide an API to set extra bottom pixels (50 in this example)
setMeasuredDimension(getMeasuredWidth(), getMeasuredHeight() + 50);
}
}
Result text view rendering without truncation at the bottom:
I am trying to display a GridView in a Dialog. Despite all my efforts, the GridView width grows to the entire screen, instead of wrapping to the columns. The layout and an image depicting the issue are below (I set a background color for the GridView to illustrate the issue).
<?xml version="1.0" encoding="utf-8"?>
<GridView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/colorgridview"
android:background="#FF00CCBB"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:numColumns="4"
android:verticalSpacing="5dp"
android:horizontalSpacing="5dp"
android:columnWidth="70dp"
android:stretchMode="none"
/>
I know that this post is a bit outdated. But if someone needs a solution to this, this answer may come in handy.
It is possible to set the view's width after screen measurement.
To do this:
Let your class implement the OnGlobalLayoutListener.
The screen is measured when the onGlobalLayout method is called. We can do our magic here.
GridView.getLayoutParams().width = ....
edit:
I wasn't very clear on how to add the onGlobalLayoutListener. See plugmind's post, he shows how to add it.
Can't figure out how to get view/layout width/height
Kind regards,
Bram
I think you should use android:layout_width="fill_parent" instead of android:layout_width="wrap_content" because wrap content use the minimum place it needs. On the other hand, fill_parent use all space needed. More over you should get rid of "android:columnWidth="70dp".
It's certainly possible to set a fixed layout_width (in dp). Since the number of your columns is also fixed, could this be a workaround for you?
Had the same problem...
I solved it with overridden onMeasure()
public class GridViewEx extends GridView {
private int mRequestedNumColumns = 0;
public GridViewEx(Context context) {
super(context);
}
public GridViewEx(Context context, AttributeSet attrs) {
super(context, attrs);
}
public GridViewEx(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
public void setNumColumns(int numColumns) {
super.setNumColumns(numColumns);
if (numColumns != mRequestedNumColumns) {
mRequestedNumColumns = numColumns;
}
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (mRequestedNumColumns > 0) {
int width = (mRequestedNumColumns * getColumnWidth())
+ ((mRequestedNumColumns-1) * getHorizontalSpacing())
+ getListPaddingLeft() + getListPaddingRight();
setMeasuredDimension(width, getMeasuredHeight());
}
}
}