I wanted to implement a custom view which is combined by a ImageView and a TextView like this.
A class called IconTextView is created by extending TextView, and the onDraw function was rewrittend by this.
#Override
protected void onDraw(Canvas canvas)
{
if (bitmap != null)
{
//something are done before
canvas.drawBitmap(bitmap, src, target, getPaint());
canvas.translate(target.right + 2, 0);
}
super.onDraw(canvas);
}
Then a IconTextView was added into the main layout like this.
<com.liujilong.carson.icontextview.IconTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
mobile:iconSrc="#drawable/ic_launcher"
android:text="myIconTextView"
android:textSize="30sp"
/>
The IconTextView shown in my phone like this.
Sorry that i can not post picture.
The problem is that the width of the View was still the width of the TextView, and I translated the canvas. So the text could not show totally.
How can I change the width of the IconTextView?
I don't think you should have to do anything as drastic as override onDraw.
You could just have a horizontal LinearLayout that has an ImageView and a TextView
Even simpler, you can set the left drawable of the TextView using the the attribute android:drawableLeft="#drawable/my_icon". If you have to change it in code, the corresponding method is TextView.setCompoundDrawablesWithIntrinsicBounds(int,int,int,int). The images would have to be set up as drawable resources for this to work.
Is there something special about your custom view that these ideas won't work?
Related
I am trying to design an UI very similar to this. I have been able to design it almost similar to the image above, but am not getting a way to implement the slanting or sloping part.
1) Can any one give an example layout of how can I implement the slanting layout?
2) And how can I place the FAB right there over the slant portion?
Any help would be really appreciated.
You can create a custom view with Slant top using Canvas and then place it over your TextView, to achieve this look and feel.
Code snippet for slant top custom view:
public class SlantView extends View {
private Context mContext;
Paint paint ;
Path path;
public SlantView(Context ctx, AttributeSet attrs) {
super(ctx, attrs);
mContext = ctx;
setWillNotDraw(false);
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
}
#Override
protected void onDraw(Canvas canvas) {
int w = getWidth(), h = getHeight();
paint.setStrokeWidth(2);
paint.setColor(Color.WHITE);
paint.setStyle(Paint.Style.FILL_AND_STROKE);
paint.setAntiAlias(true);
path = new Path();
path.setFillType(Path.FillType.EVEN_ODD);
path.moveTo(0,0);
path.lineTo(0,h);
path.lineTo(w,h);
path.close();
canvas.drawPath(path, paint);
}
}
Code snippet for how to use it with TextView
<com.pix.app.views.SlantView
android:layout_width="match_parent"
android:layout_height="30dp"
android:id="#+id/slant_view"
/>
<TextView/>
Other way to achieve Slant View is this:
<FrameLayout android:layout_height="match_parent"
android:layout_width="match_parent"
android:background="#color/colorAccent"
xmlns:android="http://schemas.android.com/apk/res/android" >
<ImageView
android:layout_width="match_parent"
android:layout_height="280dp"
android:src="#color/colorPrimary"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:rotation="-70"
android:layout_marginTop="100dp"
android:background="#color/colorAccent"></LinearLayout>
</FrameLayout>
This will give you following output:
1) Can any one give an example layout of how can I implement the slanting layout?
You cannot. Views are always rectangular. You may however make it look slanted, i.e. with background image.
2) And how can I place the FAB right there over the slant portion?
You cannot have slant. It's just bottom edge of the square bounding box. So you should be able to put it there w/o any problem.
Normally images are represented in rectangular form. You can use padding/margin to design UI according to your need. Obviously other than sloping part will be transparent image.
You need to have the root or at least the immediate parent layout as FrameLayout, then,
1) For the image part, you can have a normal ImageView to show the image. Below that you can have a LinearLayout (blank, with white background).
Now just tilt the blank LinearLayout to an angle probably 45 degrees to cut the background image in slant style. Here, just set the XML property of the blank LinearLayout,
android:rotation = "45"
2) For the FAB, just move it to the cutting point, gravity of the layout should be set to right according to your screenshot.
Hope this helps. Cheers!
You'll have to write a custom View to do it. There's no native control that can do this.
Canvas's provide support for clipping paths, so it's easy enough to clip the image provided you can draw the image. That being said, drawing large images in an OnDraw implementation is less than straightforward (memory management and correct scaling and caching behaviour isn't difficult, but it's less than trivial)
An easier way to do it would be to extend something like a FrameLayout or some kind of ViewGroup. If you override dispatchDraw, you can push a clip path onto the canvas, which will clip children. And then you can put other controls inside your custom control.
Something like this:
public class ClipFrameLayout extends FrameLayout {
.... constructors and stuff...
#Override
void dispatchDraw(Canvas canvas)
{
canvas.save();
canvas.clipPath(mCustomClipPath);
super.dispatchDraw(canvas);
canvas.restore();
}
}
Now I need to implement a function just like the html tag , see the pic below:
Firstly, I set the drawableLeft, and it show like this:
It's not my suppose do. After that I create a class 'LiTextView' implements TextView, and override the onDraw() method like this:
#Override
protected void onDraw(Canvas canvas) {
Drawable[] drawables = getCompoundDrawables();
if (drawables != null) {
Drawable drawableLeft = drawables[0];
if (drawableLeft != null) {
canvas.save();
canvas.translate(10, 50);
drawableLeft.draw(canvas);
canvas.restore();
}
}
super.onDraw(canvas);
}
the xml file like this:
<me.naiyu.android.textviewlidemo.widget.LiTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:drawableLeft="#drawable/circle_dot"
android:drawablePadding="10dp"
android:textColor="#000000"
android:textSize="18sp"
android:text="Displays text to the user and optionally allows them to edit it. A TextView is a complete text editor, however the basic class is configured to not allow editing"/>
and it became this(have two circle):
How can I implement the picture one, I now have no idear!
The reason why the "dot" is drawn twice is because you call super.onDraw(canvas). You've drawn the dot yourself in the top-position, and then you let the system draw the dot on the original position by calling the super.
Unfortunately, you have to call super.onDraw(canvas) in order to draw the text. A better approach to achieve what you want is by creating a custom Drawable that wraps the Drawable you want to display, and then override the draw(Canvas) method of the custom Drawable.
See my answer here for an example. The only downside is that you have to set the drawableLeft from code, not XML.
I'm trying to display values that a user enters on an image, there are 4 versions of image (ldpi, mdpi, hdpi and xhdpi).
I want to position the textViews on a "fixed" location that adjusts to the right screensize.
Has anyone got some advice on how I could achieve this?
Here is a sketch of what I'm trying to do.
http://dl.dropbox.com/u/251053/stackoverflow.png
edit
Thanks for the fast responses.
Uploaded a new image, this isn't possible with relative layout I guess?
http://dl.dropbox.com/u/251053/stackoverflow1.png
Look at the "RelativeLayout" documentation: http://developer.android.com/reference/android/widget/RelativeLayout.html
You will be able to put your textView around your ImageView.
The best way to solve this I think is to create a custom layout that expects the ImageView as its first child.
All the other children will be the TextView's that you can either:
position relatively to the position of your ImageView
position proportionally to the height/width of your parent custom layout that matches the height/width of your ImageView
The left/top position information of the child TextView's can be given through a custom LayoutParams class that suits your needs.
I think the best way is to create a custom view by extending View class. It is not so complicated as it may look. Here you can find more info about custom UI components.
The main idea is to override onDraw(Canvas canvas) and onMeasure(int widthMeasureSpec, int heightMeasureSpec) methods.
In onMeasure you should return the dimensions of your view and also you may calculate the size and angle of the rectangle and also the size of text you want to draw. Or you can implement custom resize() method that will be called explicitly on you view from the activity and make text and image calculations.
When you know all the measurements you can position and draw both image and text in onDraw(Canvas canvas) method.
#Override
protected void onDraw(Canvas canvas) {
myImageDrawable.setBounds(0,0,50,50);
myImageDrawable.draw(canvas);
canvas.drawText(myText, 10, 10, myTextPaint);
}
You can find more info about Canvas class here.
Also you may use StaticLayout to measure text.
Is it possible to add TextView and ImageView on canvas?
Canvas does not inherit from ViewGroup, so it does not have the ability to add child views to it.
With Canvas, you use drawBitmap and drawText methods to draw images and text instead of adding child controls like TextView and ImageView.
It's a round about way, but this tutorial adds a textview to his canvas:
http://www.helloandroid.com/tutorials/how-draw-multiline-text-canvas-easily
If you need to freely position ImageViews and TextViews, you should use a RelativeLayout.
The RelativeLayout has advanced positioning features and allows overlapping.
- put your view (which is using canvas) inside the RelativeLayout,
public class YourComponent extends View{
#Override
protected void onDraw(Canvas canvas)
...
public void onDraw(){
....
....
ImageView yourImageView = .....
RelativeLayout.LayoutParams fParams = new RelativeLayout.LayoutParams(25,25);
fParams.leftMargin = 100; //x coordinate
fParams.topMargin = 25; /y coordinate
yourImageView.setLayoutParams(fParams);
((RelativeLayout) YourComponent.this.getParent()).addView(yourImageView);
}
}
above code : i created layout params which shows 25x25 dimensions for view. and after that , i used margins to set proper position on the parent layout. and set this LayoutParams to ImageView. and for last, i added this imageView to parent Layout.
But beware that during the onDraw() execution, calling operation on external view may stop onDraw(). so if you want to use this way be sure you already completed all onDraw operation.
I am not so sure why this happens. I did not try to observe too much on it yet.
How to align the text to top of a TextView?
Equivalent Android API for Swings setInsets()?
that is top of text should start be in (0,0) of TextView
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<TextView
android:id="#+id/text1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView"
android:textSize="42sp"
android:paddingTop="0px"
android:gravity="top">
</TextView>
</LinearLayout>
I have used above snippet, however still output is not as expected
Any ideas?
So the space at the top of the TextView is padding used for characters outside the English language such as accents. To remove this space you can either set the android:includeFontPadding attribute to false in your XML or you can do it programmatically with the function setIncludeFontPadding(false).
Look at the SDK documentation for TextView if this is still unclear.
EDITED ANSWER
If setting the android:includeFontPadding attribute does not accomplish what you're trying to do, the other solution is to override the onDraw(Canvas canvas) method of the TextView that you're using so that it eliminates the additional top padding that Android adds to every TextView. After writing my original answer, I noticed that for some reason TextView includes extra padding in addition to the font padding. Removing the font padding as well as this additional padding perfectly aligns the text to the top of the TextView. Look at the code snippet below.
public class TopAlignedTextView extends TextView {
// Default constructor when inflating from XML file
public TopAlignedTextView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
// Default constructor override
public TopAlignedTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs);
setIncludeFontPadding(false); //remove the font padding
setGravity(getGravity() | Gravity.TOP); //make sure that the gravity is set to the top
}
/*This is where the magic happens*/
#Override
protected void onDraw(Canvas canvas){
TextPaint textPaint = getPaint();
textPaint.setColor(getCurrentTextColor());
textPaint.drawableState = getDrawableState();
canvas.save();
//converts 5dip into pixels
int additionalPadding = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 5, getContext().getResources().getDisplayMetrics());
//subtracts the additional padding from the top of the canvas that textview draws to in order to align it with the top.
canvas.translate(0, -additionalPadding);
if(getLayout() != null)
getLayout().draw(canvas);
canvas.restore();
}
}
In your .xml, write that:
android:gravity="center|top"
The first "center" align your line horizontally in the center and the next "top" align vertically up.
The actual font itself has extra whitespace on the top and bottom I believe.
Usually what I do is give the view negative margins. The issue is that this looks bad when devices come with different fonts.
android:layout_marginTop="-5dp"
android:layout_marginBottom="-5dp"
You will have to adjust based on the text size, bigger text sizes require more negative padding.
Possible, you do not need make your view based on TextView. Try to extend View and write your text in onDraw().
Look at here: https://stackoverflow.com/a/32081250/1263771
I think your snippet is right. I guess you are bothered by some pixels between top of the letter "T" and top edge of the TextView? This space is required to render some letters that are not present in English alphabet.
Check that links to get idea:
http://unicode.org/charts/PDF/U0400.pdf
http://en.wikipedia.org/wiki/Typeface
Im not sure if i understand what you are meaning, but the text inside the textview is going to be align to the top if you use gravity=top on the text-view.
If you put a backgrund color on you textview you might see better what is happening...
I guess you problem is that the textview is centered since you use fill_parent on both height and width on the parent LinearLayout. The textview seems to be the only child so try putting gravity=top on the LinearLayout...
Thats the only thing i could think of...