I have a layout which contains a ScrollView which contains various components including an ImageView. I've found that I can add a TouchListener to the ImageView and the x,y values I get for the event are offset from the corner of the ImageView (including padding). Thus I can easily handle touch events without worrying about the state of the ScrollView.
The problem is that I don't see a way to add a view on top of the ImageView so that I can make a visual change to the ImageView when it's touched in certain locations.
Specifically, there are various boxes in the image which I'd like to highlight when they're tapped. I can add a view to the activity, but I'd have to take the state of the ScrollView into account in order to display things in the right spot.
What's the best way to approach this? Can I derive a new version of ImageView, overload the draw method, and use that somehow? (not sure how I'd specify it in the xml, I'd probably need to set it in the onCreate of the activity)
You should be able to override the onDraw method of the ImageView as you suggested and draw stuff on top of the ImageView. The onDraw method gives you the Canvas that you could draw on. In the XML, you could just use the name of the new class you created instead of "ImageView" (unless you want to add parameters in addition to the ones offered by ImageView, this should be pretty straight forward).
<your.new.awesome.class.with.the.full.namespace
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="#+id/awesome_image_view"
/>
The problem is that I don't see a way to add a view on top of the ImageView so that I can make a visual change to the ImageView when it's touched in certain locations.
It seems that you are more comfortable with having a separate view that you could work on. You could do that by encapsulating the ImageView with a FrameLayout and then adding another view of any kind as a sibling of that ImageView. This view would be drawn on top of the ImageView if it was mentioned in the FrameLayout after the ImageView. This solution may not be the most efficient one, but it might get you started. Overriding the onDraw method of the ImageView would definitely be the best option.
you can make a relativelayout or something with a background as your desired image instead of having just an imageview. then you can have child views within that relativelayout.
Related
i'm using Eclipse to make an android app. I'm a beginner and i'm wondering how on earth I can place an image on my page where ever I want. It keeps locking in certain places due to alignments. Surely you must be able to click the image view and drag it into the desired place??
thanks
If you use RelativeLayout or FrameLayout as a container, you can place the inner Views wherever you want. They still have to be aligned somehow, but by changing the margins they can be on every position in the parent.
I began to study Android not so long ago and have a question relating to which approach I should use to solve the simple task. Let's suppose I have a view (maybe, a button) and I want user to be able to move it across the screen with a finger. Until AbsoluteLayout was deprecated, the right approach seamed obvious. I would've just changed position of my view based on corresponding events. But what is right now?
Create a custom view of your own and add a onTouch event listener. It is very simple. Explained very well here.
If you're trying to move your views in order to navigate through your application or page through images in a gallery, Android provides a collection of widgets to do things like that. If you're trying to, say, pan across a large image, maybe this will help: Image in Canvas with touch events
Im using FrameLayout and update marginLeft and marginTop
You can add multiple children to frame layout, though this is not recommended because of multiple resolutions issues.
from the android docs:
FrameLayout is designed to block out an area on the screen to display
a single item. Generally, FrameLayout should be used to hold a single
child view, because it can be difficult to organize child views in a
way that's scalable to different screen sizes without the children
overlapping each other. You can, however, add multiple children to a
FrameLayout and control their position within the FrameLayout by
assigning gravity to each child, using the android:layout_gravity
attribute.
This "warning" is not applicable in your case because you are explicitly setting the margins according to the user touch event.
I am interested in creating a ListView where each row is marked the way it is done in GMail for 3.0+. This creates a nice separation of the left and right ListFragment.
Other examples include also Google Calendar on 2.3.4 for instance where a color marker is on the left of the ListView.
See the grey vertical divider between the two lists. How does one achive something like this? A bonus would be also the alternating width, but I guess that is only a smaller layout change.
I know I could probably do something like inserting an ImageView in there and then fill it with the color I would like but it seems to me that this is an ugly hack.
Another question would be also if there is a generalized way to combine the two ListView fragments somehow the way the GMail or Mail applications do it.
If you want speed, then the option I would go for is to use a custom View class (e.g. extend RelativeLayout) for the row container View and override the dispatchDraw(Canvas canvas) method.
The dispatchDraw method is called after the View has drawn its own contents and before it draws its children - the children are drawn when you call super.dispatchDraw.
Use this to do something like
private boolean mDrawMarker = false;
public void setShouldDrawMarker(boolean drawMarker) {
mDrawMarker = drawMarker;
}
public boolean getShouldDrawMarker() {
return mDrawMarker;
}
#Override
public void dispatchDraw(Canvas canvas) {
// draw the children of our view
super.dispatchDraw(canvas);
// draw our marker on top of the children if needed
if (mDrawMarker) {
// e.g. canvas.drawRect(...) or canvas.drawBitmap(...)
}
}
This way you avoid adding any extra views to the hierarchy which means you won't incur any penalty in the layout or measuring phases. Remember to re-use Paint and Rect objects if drawing a rectangle rather than creating a new one each time. Similarly if you use a bitmap you should share the same Bitmap instance across all instances of your View rather than loading a new one from your resources each time (this does not mean putting them in static fields)
For the indentation of the items, since in this case the lists don't seem to be overlapping you could (off the top of my head):
Set a left margin on the row container (not totally sure this will work)
Wrap the row container in a LinearLayout and set the left padding on this (if the above doesn't work)
Use a custom view class (if setting the left margin doesn't work)
Go with #commonsware suggestion and use two Views - one on the left with the grey background color and another to the right of that with the marker color - then just set the view on the left to visible/gone if you want indentation/no-indentation
As for the overlapping of the Views in the second example, I'll defer to #commonsware answer.
Please tell me if I have understood the problem correctly.... You would like to mark certain rows as selected, and selected rows appear to be indented visually (with a different colour and margin)?
Here are 2 techniques:
1 - Using a StateListDrawable for the row background:
If so I would create a list row layout file and set the "background" property to a StateListDrawable (can be XML). This will allow the row to switch visual states for selected and not selected.
The "drawable" attribute of the StateListDrawable would be a 9-patch PNG, one for the un-selected state that includes no margin, and one for the selected... the selected one would define a margin within the PNG itself, by specifying the content-area/bottom black line to not extend fully to the left hand side of the PNG, leaving a region which is your unscaled margin.
For the benefit of people finding this, Radley Marx just posted an excellent post on 9 patch: http://radleymarx.com/blog/simple-guide-to-9-patch/
With ListViews it's sometimes the case you want to turn off the "listSelector" (which is a separate entity either rendered above the list, or behind) and instead use the "duplicateParentState" attribute to allow the row itself to display the selection (no list selector needed). This can provide a bit more creative freedom, especially when you want to have variable-width margins on certain rows, or several types of row that all look different. Totally depends on the design though.
2 - Using a margin for each row:
If you decided you needed multiple types of colour indicator and so on, you may have to use a different approach, providing a margin attribute (which probably won't just work straight away)... This relates to how LayoutParams are used by the layout system. I'm trying to remember the exact details, but I think this is due to the different types of LayoutParam subclass, and the properties of a MarginLayoutParam (or subclass of that) e.g. marginLeft may be ignored by the layout code of the ListView. You should be using an instance of AbsListView.LayoutParams, which includes no options for margins. One way is to nest your row inside a container View (subclass) which does allow for margins in its LayoutParams*. I'm certain I didn't end up doing this extraneous-nesting but I'll have to dig into some code to remember the better solution.
You mention putting an ImageView and filling it with colour. There are a couple of alternatives you could look at... The most performant would probably be to define your own ListRow class and use onDraw() to actually draw the row contents yourself, canvas.draw_xyz() to paint the little colour tab, and draw text etc for the rest, rather than build the row in a composite layout. The second method using layouts would be to have a lighter-weight <View layout_height="match_parent" layout_width="4dip" background="#ffff0000" /> for example.
*A golden rule in Android layout: Complex UI hierarchy is death to performance, especially with things like ListView. It's often possible to avoid this by using other things: RelativeLayout, drawableTop(etc), 9-patch images, rather than adding more Views.
If I have misunderstood and the above is just too basic please could you provide some more detail, maybe a diagram indicating the exact part you need to reproduce.
How does one achive something like this?
Off the cuff, I'd use a View with the desired background color, visible when you want it, invisible when you don't.
A bonus would be also the alternating width, but I guess that is only a smaller layout change.
I do not know what you mean by "alternating width". I think there are two Views with the desired background color in a horizontal LinearLayout, with only one visible.
I know I could probably do something like inserting an ImageView in there and then fill it with the color I would like but it seems to me that this is an ugly hack.
Well, ImageView is a bit heavier than is needed. Otherwise, I fail to see why this is a hack. Think of them as icons that simply happen to be tall, thin, gray, and not always needed.
Another question would be also if there is a generalized way to combine the two ListView fragments somehow the way the GMail or Mail applications do it.
Use a RelativeLayout, so the right-hand fragment can float over the left-hand fragment.
I've got a standard RelativeLayout laying out my Buttons and TextAreas. What I want to do now is be able to draw various sparks, flying cows etc. at arbitrary places on the screen on top of the whole thing. What's the best way to do this? Should I override onDraw() on the containing View and draw after calling super.onDraw()? Or is there some better way of drawing a layer on top?
You'll probably want to put your Relative layout and a custom view which isn't focusable and doesn't consume motionevents inside a FrameLayout, then override OnDraw in that custom view. That way you can call invalidate() on that view without making Android redraw everything else.
i have the following problem.
I am working with a library of maps which paints the icons on the map using drawables and canvas.
Now, i'm trying to modify it in order to the user can click on icons. So i want to attach drawables into different ImageView with a onClickListener.
However, i don't know how i can paint the ImageView using canvas from method onDraw.
I've tried with:
ImageView iv = new ImageView(context);
iv.setDrawableResource(drawable);
iv.draw(c)
But it doesn't appears in screen.
Any idea? Thanks
You might have better luck if you provided more context -- what's "c" represent here? But in any case, you can't just create new imageviews, you need to attach them to your layout, either by inflating them with a parent view argument from XML, or calling your parent layout's addView() programatically.
Generally, you'll rarely call any draw() methods by hand (unless you're implementing a custom view of some sort); you'll inflate your views from XML into your layout, or else instantiate your views, set whatever LayoutParams you need, and add them to a layout. The Android UI libraries handle figuring out when standard views are invalidated and need to be redrawn, for performance reasons and your own sanity.