I am making a small app for Android, where I have a RelativeLayout, which amongst other things contains a custom ImageView. In my Java code I have this class:
package com.example.android.helloactivity;
class ArrowImageView extends ImageView {
public ArrowImageView(Context context) {
super(context);
}
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawCircle(10,10,10,null);
}
}
Then in my RelativeLayout xml I have the following:
<RelativeLayout android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:background="#FFF"
xmlns:android="http://schemas.android.com/apk/res/android">
<Button ...... />
<TextView ......./>
<com.example.android.helloactivity.ArrowImageView
android:id="#+id/hello_activity_bearingarrow"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>
When I run my main class (not shown here) then my program crashes. If I omit the xml reference to ArrowImageView, then it does not crash.
Am I referring to my custom class te wrong way, or what is going on?
When extending the View widgets, if you plan to use them in XML layouts you need to also override the constructors that take the AttributeSet argument.
First don't extend ImageView but just View, unless there is something special about ImageView that you know and want to use.
Second, as Leffel said, you need to state attribute set like this
public ArrowImageView(Context context, AttributeSet set) {
super(context, set);
}
Also you may need to give some size to the custom view by setting witdh and height to something like 100dp. I am not sure what a custom View can "wrap" when there is no other views inside.
Thanks for the answers. I found a bug in the onPaint method itself which still made things crash. After implementing your suggestions and changing the onPaint into:
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint = new Paint();
paint.setColor(Color.MAGENTA);
canvas.drawCircle(10,10,10,paint);
}
everything worked!
Thank you very much for your help :-)
Related
I programatically moved a layout with several child views. The child views all display in their new positions. However, the click and touch events are still working as if the views were in their old positions. What do I do?
Edit:
I used translate and scale to move the layout. Here is the code from a class extending LinearLayout:
#Override
protected void onDraw(Canvas canvas) {
canvas.translate(getWidth(), 0);
canvas.scale(-1, 1);
super.onDraw(canvas);
}
I use this new layout in multiple activities, but the issue is the same for all of them. Here is one of the simpler layouts:
<?xml version="1.0" encoding="utf-8"?>
<com.example.myapp.NewLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<GridView
android:id="#+id/chapter_gridview"
style="#style/GridStyle" />
</com.example.myapp.NewLayout>
Any solutions?
Update
One way may be to update the LayoutParams but I am not sure how to do that yet. These are some related questions I found:
OnClickListener issues after ImageButton moved after TranslateAnimation
How can I dynamically set the position of view in Android?
http://www.clingmarks.com/how-to-permanently-move-view-with-animation-effect-in-android/400
Edit
No solutions? I give up then.
If you are working with AnimationTranslation :
Your LinearLayout had been moved seemingly,but it's just visually moved.The LinearLayout is still where it is before the animation.
try this to your layout :
mylayout.layout(x,x,x,x);
I took my answer from here
you can also see this question
EDIT
If you are working with Canvas.translate :
try padding in place of translate : canvas.setPadding(getWidth(), 0);
Can anyone explain to me why this is happening?
I have a fairly simple class extending TextView. When I set the background colour to Color.BLUE, padding works fine. When I change the background resource to android.R.drawable.list_selector_background, my padding is no longer applied. What the F?
Here is my UI class:
public class GhostDropDownOption extends TextView {
TextView text_view;
public GhostDropDownOption(Context context, AttributeSet attrs) {
super(context, attrs);
setup(context);
}
public GhostDropDownOption(Context context) {
super(context);
setup(context);
}
private void setup(Context context) {
this.setClickable(false);
// THE 2 LINES BELOW ARE THE ONLY THING I'M CHANGING
//this.setBackgroundResource(android.R.drawable.list_selector_background);
this.setBackgroundColor(Color.BLUE);
}
}
And I'm using it in the layout like this:
<trioro.voyeur.ui.GhostDropDownOption
android:id="#+id/tv_dropdown_option_1"
android:layout_width="fill_parent"
android:layout_height="0dip"
android:layout_weight="1"
android:gravity="center_vertical"
android:text="#string/request_control_dropdown_option_1"
android:textColor="#000000"
android:padding="10dip"/>
And this is the result of changing the background:
The call to:
this.setBackgroundResource(android.R.drawable.list_selector_background);
will remove any previosly set padding (this is to make it work properly with 9-patch assets).
Try to set the padding in code after the line above, like this:
this.setPadding(PADDING_CONSTANT, PADDING_CONSTANT, PADDING_CONSTANT, PADDING_CONSTANT);
Just remember that the values sent to setPadding is in pixels NOT dip!
You should set your background drawable in XML if at all possible. If you set it in code, it will use the padding from your drawable resources rather than what you set in XML, so if it's necessary to do it programmatically, you'll want to retrieve the current padding, store it temporarily, set the background, and then set the padding back as #TofferJ suggests.
The reason for this is that the drawables themselves can have padding, in the case of 9-patch images (where the bottom and right pixel borders define the amount of padding).
Your solution should be to just set your background resource in XML:
android:background="#android:drawable/list_selector_background"
although I believe that may be a private drawable resource that you'll have to copy into your project first.
I've created a custom view which extends RelativeLayout, and I want to preview how it looks in the designer.
The java is something like this:
// The view for a snap in the search/browse fragment.
public class MyView extends RelativeLayout
{
public MyView(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
LayoutInflater inflater = LayoutInflater.from(context);
inflater.inflate(R.layout.the_layout, this);
}
public void setData(String text)
{
mText.setText(text);
}
// *** Views ***
private TextView mText;
#Override
protected void onFinishInflate()
{
super.onFinishInflate();
mText = (TextView)findViewById(R.id.text);
}
}
And the XML is like this:
<?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" >
<TextView
android:id="#+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<!-- (And lots more views) -->
</RelativeLayout>
There are a few problems with this however:
This actually creates a RelativeLayout within a RelativeLayout which is pointless. It can be solved by changing the XML <RelativeLayout> to a <merge> but then I can't preview the layout at all!
I want to use the isInEditor() function (or whatever it is called) in the java to add some sample data for previewing purposes, but I can't find a way to tell the XML editor that it should display a preview of my class instead of the actual XML.
One unsatisfying solution I can think of is to create an empty preview.xml file with only <com.foo.bar.MyView/> in it... But that seems kind of silly. Is there a better way? (I don't really care about editing as much as previewing, since - let's face it - Eclipse/ADT are way too slow and flaky to make graphical layout editing usable.)
If I understand your problem correctly I would say that the solution is to just replace the "RelativeLayout" tags (or any other tag for that matter) in your xml layout with "your.packagename.MyView" as in:
<your.packagename.MyView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<!-- (And lots more views) -->
</your.packagename.MyView>
If you'll get any exceptions regarding MyView class while running your app, add all the missing super/parent constructors.
I do this for almost all of my custom xml layouts. Extending your class with RelativeLayout, LinearLayout or any other GUI class also gives you great controll over how your GUI should behave (because you can also override parent methods etc.).
I created a background image bitmap for a view and now the view is being stretched to the size of the background image....
is this normal?
<?xml version="1.0" encoding="utf-8"?>
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
android:src="#drawable/green"
android:tileMode="repeat"/>
here's how I apply it to my view
v.setBackgroundResource(R.drawable.backgroundgreen);
for instance...
if the image is 500px in height
and the view is 200px in height(being set wrap_content as height)
after setting the image as background my view becomes 500px in height...
I have faced this same problem.
If the background image has a size that is bigger than the view's size, the view's size will change to match the image's size.
Solution
Put the view inside a Relative Layout.
Remove the background image.
Add an ImageView before the View inside the Relative Layout
Set the src of the ImageView to your background image
<RelativeLayout
.
.
. >
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="#+id/yourViewId"
android:layout_alignRight="#+id/yourViewId"
android:layout_alignTop="#+id/yourViewId"
android:layout_alignBottom="#+id/yourViewId"
android:adjustViewBounds="true"
//this will allow the image to resize with same proportions
android:src="#drawable/yourDrawable" />
<YourView
android:id="#+id/yourViewId"
.
..
... />
</RelativeLayout>
This all can be done in code of course.
According to me, the problem you are facing is not a problem, it is the way how Android is used to design the layouts.
This means that you can set the height and width with 3 default constant values:
FILL_PARENT
Special value for the height or width requested by a View. FILL_PARENT means that the View wants to be as big as its parent, minus the parent's padding if any. This value is deprecated starting in API Level 8 and replaced by MATCH_PARENT.
MATCH_PARENT
Special value for the height or width requested by a View. MATCH_PARENT means that the view wants to be as big as its parent, minus the parent's padding if any. Introduced in API Level 8.
WRAP_CONTENT
Special value for the height or width requested by a View. WRAP_CONTENT means that the View wants to be just large enough to fit its own internal content, taking its own padding into account.
Now, when you are setting the View's height/width to WRAP_CONTENT, you are allowing the view to take that much size that is sufficient to show to view's content. The background image is also the View's content, hence you view will be shown of as much size as the image. That's not a problem, that's how it's shown.
Okay, but in your situation that's an issue for you because you have a background to show and view should not be stretched for that. I can suggest few ways:
First and very obvious: make correctly sized images and keep them in different drawable folders.
Specify the size of view not using constants, but in DP. If it becomes necessary, make different layout XML files for different sizes and keep them in layout folders.
You can use a very useful thing for design layout is layout weight.
I suggest to create a wrapper layout and put the background image in there. i'm using it that way and fits very nicely.
see example below
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/settingstab_scroll"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:scrollbars="vertical"
android:background="#drawable/wareninja_wallpaper_img"
>
<!-- your layouts and components goes here -->
</ScrollView>
...
Social Coding # AspiroTV
The reason is quite simple. You gotta see the View::getSuggestedMinimumWidth/Height method.
protected int getSuggestedMinimumWidth() {
return (mBackground == null) ? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth());
}
protected int getSuggestedMinimumHeight() {
return (mBackground == null) ? mMinHeight : max(mMinHeight, mBackground.getMinimumHeight());
}
Seeing that, you may know why the background makes a view bigger, especially why assign a BitmapDrawable to it.
and the simple solution is to wrap that Drawable (eg. BitmapDrawable), then returns 0 for getMinimumHeight() and getMinimumWidth(), and better to override getIntrinsicHeight() and getIntrinsicWidth() to returns -1.
support-v7 has a DrawableWrapper which delegates calls to another drawable when necessary. you can extends that one and override methods talked above.
and if you don't use support-v7 (WoW! you are awesome), copy that class to your project is also fine.
https://android.googlesource.com/platform/frameworks/support/+/1949ae9aeaadf52ad7bd7bb74ca5419c67ea7f65/v7/appcompat/src/android/support/v7/internal/widget/DrawableWrapper.java
It's working for me.
< ?xml version="1.0" encoding="utf-8"?>
< LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent" android:id="#+id/LinearLayoutTest">
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.prueba);
((LinearLayout)findViewById(R.id.LinearLayoutTest)).setBackgroundResource(R.drawable.greenrepeat);
}
in your code, what is v? It has params to fill_parent?
Don't use android:tileMode="repeat". Is your green drawable bigger or smaller than your view? Could add more details?
One good solution that is working perfectly in my case is extending the View and overriding onMeasure().
Here is the steps to do:
Create an own class and extend the View you want to use, here for
example I will use Button.
Override the method onMeasure() and insert the code at the bottom. This will set the background resource after the first measure has been done. For the second measure event, it will use the already measured paramters.
Example code for a custom view which extends Button (change Button to the View you would like to extend)
public class MyButton extends Button {
boolean backGroundSet = false;
public MyButton(Context context) {
super(context);
}
public MyButton(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if(backGroundSet) {
setMeasuredDimension(getMeasuredWidth(), getMeasuredHeight());
return;
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
backGroundSet = true;
setBackgroundResource(R.drawable.button_back_selector);
}
}
The only thing to change here is the type of view you want to extend and in the onMeasure() method the background resource you want to use for the view.
After that, just use this view in your layout xml or add it programatically.
I modify Sherif elKhatib's code, now this works for me:
if we want background picture be stretched as view picture:
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignStart="#+id/yourViewId"
android:layout_alignTop="#+id/yourViewId"
android:layout_alignEnd="#+id/yourViewId"
android:layout_alignBottom="#+id/yourViewId"
android:scaleType="fitXY"
android:src="#drawable/bg_very_big_picture" />
<LinearLayout
android:id="#+id/yourViewId"
android:layout_width="match_parent"
android:layout_height="wrap_content"
if we want background picture not to be stretched, but to be cutted to fit view picture:
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignStart="#+id/yourViewId"
android:layout_alignTop="#+id/yourViewId"
android:layout_alignEnd="#+id/yourViewId"
android:layout_alignBottom="#+id/yourViewId"
android:scaleType="centerCrop"
android:src="#drawable/bg_very_big_picture" />
<LinearLayout
android:id="#+id/yourViewId"
android:layout_width="match_parent"
android:layout_height="wrap_content"
Can someone tell me if this is a bug in the SDK/IDE:
Any custom or extended layout I add to my layout XML causes the IDE to ignore the fact that there are any child views of that layout (they just disappear from the outline view/window), thus making them uneditable via the properties view/window. (I need to extend a layout to make onSetAlpha() public)
FYI: I'm developing for Android 1.5 and up, using all the latest plug-ins/updates in Eclipse
Here is a simple example of a layout XML and the extended Layout that causes this error.
[Extended Layout]
package com.test;
public class CustomLinearLayout extends LinearLayout
{
public CustomLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomLinearLayout(Context context) {
super(context);
}
}
[Simple layout XML]
<?xml version="1.0" encoding="utf-8"?>
<com.test.CustomLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView android:id="#+id/ImageView01"
android:layout_width="wrap_content"
android:layout_height="wrap_content"></ImageView>
</com.test.CustomLinearLayout>
ImageView01 is not visible or editable in the properties or outline views/windows.
Thanks.
When you want to edit the properties of view just replace your com.test.CustomLinearLayout
with LinearLayout.
Then you can see the view in properties and can edit the properties. After you finish editing then revert the tag to original one that is from LinearLayout to com.test.CustomLinearLayout