I need to add Arrow to Next Button like that
What's the easiest way to achieve that? Making custom Compound view sounds like overkill
PS Symbol > is not nice.
Just use a TextView.
<TextView
android:id="#+id/some_id"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/next"
android:drawableRight="#drawable/arrow_right"
android:clickable="true"
android:focusable="true"
android:background="?android:selectableItemBackground"
/>
TextViews have support for compound drawables, where you can specify a drawable you want to be displayed next to the text. It can be above, below, right, left, start, end.
Notice also that I set the TextView to be clickable and focusable and that I gave it Android's default ripple background (where it shows the ripple effect when pressed).
EDIT
If you need the arrow to be directly after the text, you have to use a container and child Views:
<LinearLayout
android:id="#+id/button_wrapper"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:clickable="true"
android:focusable="true"
android:background="?android:selectableItemBackground">
<TextView
android:id="#+id/some_textview"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="#string/next" />
<ImageView
android:id="#+id/some_image"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:src="#drawable/arrow_right" />
</LinearLayout>
You'll want to set your click listener on the LinearLayout.
Alternatively, use the U+276fa character as part of your TextView's text: ❯. It's not > and looks more like an arrow.
Try this custom button, it calculates where to put the icon directly next to the text.
public class CenteredIconButton extends Button {
private static final int LEFT = 0, TOP = 1, RIGHT = 2, BOTTOM = 3;
private Rect textBounds = new Rect();
private Rect drawableBounds = new Rect();
public CenteredIconButton(Context context) {
this(context, null);
}
public CenteredIconButton(Context context, AttributeSet attrs) {
this(context, attrs, android.R.attr.buttonStyle);
}
public CenteredIconButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
if (!changed) return;
final CharSequence text = getText();
if (!TextUtils.isEmpty(text)) {
TextPaint textPaint = getPaint();
textPaint.getTextBounds(text.toString(), 0, text.length(), textBounds);
} else {
textBounds.setEmpty();
}
final int width = getWidth() - (getPaddingLeft() + getPaddingRight());
final int height = getHeight() - (getPaddingTop() + getPaddingBottom());
final Drawable[] drawables = getCompoundDrawables();
if (drawables[LEFT] != null) {
drawables[LEFT].copyBounds(drawableBounds);
int leftOffset =
(width - (textBounds.width() + drawableBounds.width()) + getRightPaddingOffset()) / 2 - getCompoundDrawablePadding();
drawableBounds.offset(leftOffset, 0);
drawables[LEFT].setBounds(drawableBounds);
}
if (drawables[RIGHT] != null) {
drawables[RIGHT].copyBounds(drawableBounds);
int rightOffset =
((textBounds.width() + drawableBounds.width()) - width + getLeftPaddingOffset()) / 2 + getCompoundDrawablePadding();
drawableBounds.offset(rightOffset, 0);
drawables[RIGHT].setBounds(drawableBounds);
}
if (drawables[TOP] != null) {
drawables[TOP].copyBounds(drawableBounds);
int topOffset =
(height - (textBounds.height() + drawableBounds.height()) + getBottomPaddingOffset()) / 2 - getCompoundDrawablePadding();
drawableBounds.offset(topOffset, 0);
drawables[TOP].setBounds(drawableBounds);
}
}
}
Related
In TextView I set drawableLeft where the drawable is showing from center. I need to align the drawableLeft with top inside TextView like this image.
Is it possible to achieve this?
Use SpannableString and ImageSpan to achieve this.
String msg=" "+"haii";
ImageSpan mImageSpan== new ImageSpan(mContext, R.drawable.icon);
SpannableString text = new SpannableString(msg);
text.setSpan(mImageSpan, 0, 1, 0);
mTextView.setText(text);
the extra space in the string variable is replaced by the icon.
I think it's even easier than all the answers above: You only need to do this:
public class TopGravityDrawable extends BitmapDrawable {
public TopGravityDrawable(Resources res, Bitmap bitmap) {
super(res, bitmap);
}
#Override
public void draw(Canvas canvas) {
int halfCanvas = canvas.getHeight() / 2;
int halfDrawable = getIntrinsicHeight() / 2;
canvas.save();
canvas.translate(0, -halfCanvas + halfDrawable);
super.draw(canvas);
canvas.restore();
}
}
And then
final Bitmap bitmap = BitmapFactory.decodeResource(mTitle.getResources(), R.drawable.icon);
icon = new TopGravityDrawable(mTitle.getResources(), bitmap);
title.setCompoundDrawablesWithIntrinsicBounds(icon, null, null, null);
Remember this only works properly with LEFT and RIGHT compound drawables
See my answer here.
You can align a compound-Drawable to the top (or bottom) by creating a custom Drawable that wraps your Drawable, and then manipulate the drawing of your custom Drawable by overriding the method onDraw(Canvas).
The sample below is the simplest possible example. This aligns the image to the top, but you can also make it align to the bottom, left or right of the TextView by implementing the required logic in the onDraw(Canvas)-method. You might also want to build in a margin in the onDraw(Canvas), to make your design implementation pixel perfect.
Sample usage:
GravityCompoundDrawable gravityDrawable = new GravityCompoundDrawable(innerDrawable);
// NOTE: next 2 lines are important!
innerDrawable.setBounds(0, 0, innerDrawable.getIntrinsicWidth(), innerDrawable.getIntrinsicHeight());
gravityDrawable.setBounds(0, 0, innerDrawable.getIntrinsicWidth(), innerDrawable.getIntrinsicHeight());
mTextView.setCompoundDrawables(gravityDrawable, null, null, null);
Sample code:
public class GravityCompoundDrawable extends Drawable {
// inner Drawable
private final Drawable mDrawable;
public GravityCompoundDrawable(Drawable drawable) {
mDrawable = drawable;
}
#Override
public int getIntrinsicWidth() {
return mDrawable.getIntrinsicWidth();
}
#Override
public int getIntrinsicHeight() {
return mDrawable.getIntrinsicHeight();
}
#Override
public void draw(Canvas canvas) {
int halfCanvas= canvas.getHeight() / 2;
int halfDrawable = mDrawable.getIntrinsicHeight() / 2;
// align to top
canvas.save();
canvas.translate(0, -halfCanvas + halfDrawable);
mDrawable.draw(canvas);
canvas.restore();
}
}
you can do like this:
public class DrawableTopLeftTextView extends TextView {
public DrawableTopLeftTextView(Context context) {
super(context);
}
public DrawableTopLeftTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public DrawableTopLeftTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
protected void onDraw(Canvas canvas) {
if (!TextUtils.isEmpty(getText())) {
Drawable[] drawables = getCompoundDrawables();
if (drawables != null) {
Drawable drawableLeft = drawables[0];
if (drawableLeft != null) {
Paint.FontMetricsInt fontMetricsInt = getPaint().getFontMetricsInt();
Rect bounds = new Rect();
getPaint().getTextBounds((String) getText(), 0, length(), bounds);
int textVerticalSpace = Math.round(bounds.top - fontMetricsInt.top);
int offset = (getHeight() - drawableLeft.getIntrinsicHeight()) / 2 - textVerticalSpace - getPaddingTop() / 2;
drawableLeft.setBounds(0, -offset, drawableLeft.getIntrinsicWidth(), drawableLeft.getIntrinsicHeight() - offset);
}
}
}
super.onDraw(canvas);
}
}
If you want a purely XML solution then you can use an inset drawable to re-position your desired drawable.
<?xml version="1.0" encoding="utf-8"?>
<inset
xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="#drawable/actual_image_to_be_shown"
android:insetTop="-32dp" />
You might have to play around with the inset value depending on your scenario. Then just use this XML drawable in your TextView drawableLeft/Start definition.
Your can use by this way. May it can helpful you.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="100dp"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true" >
<ImageView
android:id="#+id/imageView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:src="#drawable/ic_launcher" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="#+id/imageView1"
android:text=" Text Text Text Text Text Text Text Text Text Text Text Text
Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text" />
</RelativeLayout>
Try like this:
class MyTextView #JvmOverloads constructor(context: Context, attrs: AttributeSet? = null
) : AppCompatTextView(context, style) {
private val leftDrawable = ContextCompat.getDrawable(context, R.drawable.checkmark)
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
setBulletPoint(compoundDrawables[0], canvas)
}
private fun setBulletPoint(drawableLeft: Drawable?, canvas: Canvas?) {
if (!TextUtils.isEmpty(text)) {
leftDrawable?.let { drlft ->
if (lineCount == 1) {
setCompoundDrawablesWithIntrinsicBounds(drlft, null, null, null)
} else {
val buttonWidth = drlft.intrinsicWidth
val buttonHeight = drlft.intrinsicHeight
val topSpace = abs(buttonHeight - lineHeight) / 2
drlft.setBounds(0, topSpace, buttonWidth, topSpace + buttonHeight)
canvas?.apply {
save()
drlft.draw(canvas)
restore()
}
}
}
}
}
}
I'm trying to create an EditText that has a Label inside the EditText and I've been using the second suggestion of the accepted answer here.
I've managed to sort of get it working, but with a few problems. Here's how it currently looks:
That's fine, until you try and enter some text. Initially there is no margin between the label and the entered text:
Also, the label cannot be removed with backspace, but it does disappear when you enter enough text to push it off the left:
Here is the code for my custom EditText - almost the same as in the thread mentioned above:
public class KingdomSpasEditText extends EditText {
private int paddingLeft;
private String label = "";
public KingdomSpasEditText(Context context) {
super(context);
paddingLeft = getPaddingLeft();
}
public KingdomSpasEditText(Context context, AttributeSet attrs) {
super(context, attrs);
paddingLeft = getPaddingLeft();
label = attrs.getAttributeValue("http://www.kingdomspas.com/android/custom", "label");
if (label == null) {
label = "";
}
}
protected void onDraw(Canvas canvas) {
TextPaint textPaint = getPaint();
Rect size = new Rect();
textPaint.getTextBounds(label, 0, label.length(), size);
setPadding(paddingLeft + size.width(), getPaddingTop(), getPaddingRight(), getPaddingBottom());
super.onDraw(canvas);
canvas.drawText(label, paddingLeft + size.left, size.bottom + getPaddingTop() + 50, textPaint);
}
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
You may notice that in the drawText() I am adding 50 to the top padding. If I don't it looks like this:
This seems like a hack to me.
Here is the XML used to create each EditText - the only difference being the label. They are both in a TableRow which is, obviously, part of a TableLayout:
<com.kingdomspas.android.kingdomspasforms.formfields.KingdomSpasEditText
android:id="#+id/editText1" android:layout_width="fill_parent"
android:layout_height="wrap_content" android:maxLines="1"
android:singleLine="true" android:background="#drawable/round"
android:paddingTop="2dp"
android:paddingLeft="8dp"
android:layout_weight="1"
kingdomspas:label="Test Text 1: ">
<requestFocus />
</com.kingdomspas.android.kingdomspasforms.formfields.KingdomSpasEditText>
OK, thanks for sticking with me. Here is a summary of my problems:
1) How can I create a margin between the label and the entered text?
2) How can I prevent the label disapearing of to the right?
3) Is there a better way of my label in the Edittext
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"/>
I'm pretty much new in programing for Android. My app is sample app from api demos on developer android website. When I change parameters in that sample drawing it gets larger . That drawing needs to be displayed in scroll view (it doesn't need to be shrinked to fit the screen). This is the code I used:
DrawPoints.java
public class DrawPoints extends myActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.routes);
}
public static class SampleView extends View {
private Paint mPaint = new Paint();
private float[] mPts;
/*here comes declaration of parametars
private void buildPoints() {
/*here comes some coding*/
}
}
public SampleView(Context context, AttributeSet attributeset) {
super(context, attributeSet);
buildPoints();
}
#Override
protected void onDraw(Canvas canvas) {
Paint paint = mPaint;
//here also comes code
}
}
}
here is xml Code:
routes.xml
<?xml version="1.0" encoding="utf-8"?>
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/scrollView1"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<HorizontalScrollView
android:id="#+id/scrollView2"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<!-- This code is just to make sure that scroll views work how
I want them to work, image size is 625*351 px
<ImageView
android:id="#+id/image_View1"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:src="#drawable/bus_design"
/> -->
<my.package.DrawPoints.SampleView
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
</HorizontalScrollView>
</ScrollView>
When I run that application and push the button in main activity application crashes.
Drawing looks like Figure1 when I'm not using xml layout or scrollviews:
http://i.stack.imgur.com/za5MP.png
Figure1
I also tried to use this code after method setContentView:
View v = new SampleView(this);
addContentView(v, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
ViewGroup.LayoutParams.FILL_PARENT));
and also this one:
View v = new SampleView(this);
ScrollView.LayoutParams lp = new ScrollView.LayoutParams(1000, 1000);
addContentView(v, lp);
when I use codes, shown above, app displays Figure1 without scrollview, it seems like second content view overwrites that xml but it doesn't show correctly.
After that I tried to use this code after setContentView:
View v = new SampleView(this);
FrameLayout fl = new FrameLayout(this);
fl.findViewById(R.id.FrameLayout1);
fl.addView(v);
Frame layout (FrameLayout1) is added in routes.xml file after horizontal scroll view. When application runs I get blank screen without Figure1.
Does Anyone have an idea how to upgrade my code that would display Figure1 in ScrollView?
Thanks in advance!
write this line in your touchevent of custom View class
getParent().requestDisallowInterceptTouchEvent(true)
finally I found solution to my problem. I used solution from this site:
Link1
well I saw that solution before, but unfortunately I didn't realize that this solution is good for me. I knew that I need onMeasure method for Canvas to show it in xml, but withouth of solution from mentioned site it didn't work. Now it works. Here is my xml, and SampleView solution.
XML code:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/app_layout" android:orientation="horizontal"
android:layout_width="fill_parent" android:layout_height="fill_parent">
<!-- SCENE -->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/scene_layout"
android:drawingCacheQuality="low"
android:orientation="horizontal" android:layout_width="fill_parent"
android:layout_height="fill_parent">
<com.testiranje.Kristijan.TwoDScrollView
android:id="#+id/scene_scroller" android:drawingCacheQuality="low"
android:scrollbars="horizontal"
android:layout_width="fill_parent" android:layout_height="fill_parent">
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/scene_container"
android:drawingCacheQuality="low"
android:background="#drawable/map"
android:layout_width="fill_parent" android:layout_height="fill_parent">
<com.testiranje.Kristijan.SampleView
android:layout_height="fill_parent"
android:layout_width="fill_parent">
</com.testiranje.Kristijan.SampleView>
<!-- <ImageView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/scene_background" android:drawingCacheQuality="low"
android:background="#drawable/map"
android:layout_width="fill_parent" android:layout_height="fill_parent" /> -->
</RelativeLayout>
</com.testiranje.Kristijan.TwoDScrollView>
</RelativeLayout>
</RelativeLayout>
This is my SampleView solution:
public class SampleView extends View {
private Paint mPaint = new Paint();
private float[] mPts;
private static final float SIZE = 1000;
private static final int SEGS = 50;
private static final int X = 0;
private static final int Y = 1;
private void buildPoints() {
final int ptCount = (SEGS + 1) * 2;
mPts = new float[ptCount * 2];
float value = 0;
final float delta = SIZE / SEGS;
for (int i = 0; i <= SEGS; i++) {
mPts[i*4 + X] = SIZE - value;
mPts[i*4 + Y] = 0;
mPts[i*4 + X + 2] = 0;
mPts[i*4 + Y + 2] = value;
value += delta;
}
}
public SampleView(Context context){
super(context);
//initSampleView();
buildPoints();
}
//This constructor is very important because withouth of this
//you can't insert this view in xml
public SampleView(Context context, AttributeSet attrs) {
super(context, attrs);
//initSampleView();
buildPoints();
}
/*private final void initSampleView() {
mPaint = new Paint();
mPaint.setAntiAlias(true);
setPadding(3, 3, 3, 3);
}*/
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(measureWidth(widthMeasureSpec),
measureHeight(heightMeasureSpec));
}
/**
* Determines the width of this view
* #param measureSpec A measureSpec packed into an int
* #return The width of the view, honoring constraints from measureSpec
*/
private int measureWidth(int measureSpec) {
int result = 0;
//This is because of background image in relativeLayout, which is 1000*1000px
measureSpec = 1001;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
if (specMode == MeasureSpec.UNSPECIFIED) {
// We were told how big to be
result = specSize;
}
return result;
}
/**
* Determines the height of this view
* #param measureSpec A measureSpec packed into an int
* #return The height of the view, honoring constraints from measureSpec
*/
private int measureHeight(int measureSpec) {
int result = 0;
//This is because of background image in relativeLayout, which is 1000*1000px
measureSpec = 1001;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
if (specMode == MeasureSpec.UNSPECIFIED) {
// Here we say how Heigh to be
result = specSize;
}
return result;
}
#Override
protected void onDraw(Canvas canvas) {
Paint paint = mPaint;
canvas.translate(10, 10);
paint.setColor(Color.RED);
paint.setStrokeWidth(0);
canvas.drawLines(mPts, paint);
paint.setColor(Color.BLUE);
paint.setStrokeWidth(3);
canvas.drawPoints(mPts, paint);
}
}
Now I got this image, when I run my app:
http://i.stack.imgur.com/lWhvT.png
If anyone have questions about this feel free to ask me :).
I have a TextView which height is dynamic. I want to set that the last line wouldnt be visible if it cannot be fully drawn.
screenshot
The reason why height is dynamic is that it is used in an AppWidget, and the size of an appwidget is not the same on different devices. Because of this you cannot measure the TextView or cannot use a subclass of a TextView.
link
This is what I use now basically. When I put a long text into the TextView the last line looks ugly.
<LinearLayout
android:id="#+id/widgetContent"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<TextView
android:id="#+id/sg"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
I've faced this problem recently and used another solution.
I'm setting the maxLines dynamically:
final TextView tv = ((TextView) myLayout.findViewById(R.id.mytextview));
tv.setText(value);
ViewTreeObserver vto = tv.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
private int maxLines = -1;
#Override
public void onGlobalLayout() {
if (maxLines < 0 && tv.getHeight() > 0 && tv.getLineHeight() > 0) {
int height = tv.getHeight();
int lineHeight = tv.getLineHeight();
maxLines = height / lineHeight;
tv.setMaxLines(maxLines);
}
}
});
Try this
Paint paint = new Paint();
// set paint with all current text properties of the textview. like text size, face etc,
textPixelLenght = paint.measureText(mText);
int textviewWidth = mTextView.getMeasuredWidth();
int numberOfLines = textPixelLenght /textviewWidth;;
int textlineHeight = textview.getLineHeight ();
if (textlineheight * numberOfLines > textviewHeight) {
// text going beyond textviews height. Ellipsize the text using
// TextUtils.ellipsize(params);
}
You need to know the spacing of your font -
ie, if you know its 20 characters per line, and you know each full line is 10px high, then you should dynamically assign the text to the TextView:
String toAdd = "";
for (int i=0; i < textViewHeight; i+= textHeight)
toAdd += fullText.subString(i, i+charactersPerLine);
A solution to your problem would be to create a custom TextView and override the onDraw() method of the TextView. There you could manage the way this TextView handles this case.
Using the height of the font dynamically change the height of the view, ie
If your text is 10px high, your TextView can only be 10, 20, 30px high. This doesn't require you to have any particular style of font.
This solution doubles the measure pass, but because this is a text view with no children the impact shouldn't be too great. This also won't help with a widget, as it's a custom text view. Sorry!
public class ExactWrappingTextView extends TextView{
public ExactWrappingTextView(Context context) {
super(context);
}
public ExactWrappingTextView(Context context, AttributeSet attrs){
super(context, attrs);
}
public ExactWrappingTextView(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
}
private int measureHeight;
private int extraSpace;
//This doubles the measure pass for this view... but we have to know how
//high it would have been before we can pull off the right amount
public void onMeasure(int width, int height){
super.onMeasure(width, height);
extraSpace = (getMeasuredHeight() - (getPaddingTop() + getPaddingBottom())) % getLineHeight();
measureHeight = MeasureSpec.makeMeasureSpec(getMeasuredHeight() - extraSpace, MeasureSpec.AT_MOST);
super.onMeasure(width, measureHeight);
}
}