As I am actually not very confident with programatically changing Views, I have following problem:
At the first start of my app, I want to have an overlay for the main screen, that tells the user to have a look at the settings, as there are two critical options the user has to configure.
I don't want to use an AlertDialog and rather not use a wizard. So, I decided to take an approach similar to Go SMS and create an overlay at the first start. The mockup I created looks like this:
Normal menu:
First start:
So these are the problems I have:
Like I said, I don't want to use a screenshot overlaying on first start, as this would take too much space and would not be language and screen independent.
I would have the circle as an png, but I don't know how exactly put it over the image
The same problem with the text
And finally I want to put a semi-transparent white over the app. It does not necessarily need the hole for the icon, though it would be nice.
In case you need the Layout Source, you can get it at pastebin
So, I just need to get a start here, if it is better to use LayoutInflater or ViewStub and how to realize it, as I have absolutely no experience with it...
Thanks!
/edit: I uploaded a new, more well-arranged layout.
I have faced a similar problem, I client wanted a walkthrough of the application, where the entire screen had to become whiter (as they said: "transparent"), except for the button being explained by an overlay speech-bubble.
Fortunately for you, your layout is not nearly as complicated as the one I had to work with :)
Now, you can get the transparency-effect in two ways, either have a white background and call all the views setAlpha() methods, or you can create a half-transparent white overlay.
If you go with the overlay, you'll have to find a way to display the opaque buttons through the overlay. This can get a bit complicated.
If you go with the first option, you can just setAlpha(1) on the opaque view to get it to show up.
The setAlpha() method is only available from api version 11+, so if you target an earlier version, you might have to do it in a slightly more complicated way.
Example of setting alpha on views pre-honeycomb:
Layout for your buttons (make them however you want, just make them similar so you can loop through them):
<LinearLayout
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<ImageView
android:tag="image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/tile"/>
<TextView
android:tag="text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#FF000000"
android:text="button1"/>
</LinearLayout>
In your program, when you are want to make the buttons transparent:
LinearLayout l = (LinearLayout) findViewById(R.id.button1);
((ImageView)l.findViewWithTag("image")).setAlpha(0x7F);
((TextView)l.findViewWithTag("text")).setTextColor(0x7F000000);
When you have decided on how you want to create the transparency effect, you will have to decide on how to display the overlay-text/bubble. You'll most likely want to put this in a separate layer on top of your entire layout, to make sure that it is not affected by your new view.
One way to achieve this is by changing your root layout element to a FrameLayout, and then creating/displaying in this. e.g:
<FrameLayout background="#FFFF"> <!-- white background, just in case -->
<LinearLayout>
<!-- the rest of your layout -->
</LinearLayout>
<LinearLayout visibility="gone"> <!-- this will be your overlay view -->
<ImageView /> <!-- the arrow/ring -->
<TextView /> <!-- the description -->
</LinearLayout>
</FrameLayout>
When the introduction is displayed, you set the position of the hidden overlay-view to the position of the table item to be explained, change the text to an appropriate string/resource and display the view.
When the introduction is over, you reset the alpha values of all buttons, and set the visibility of the overlay to gone again.
Since I don't have much experience with ViewStub, I would do it with LayoutInflater.
First of all, you need to have a second layout loaded on top of your current layout. The easiest is to have a FrameLayout, which has as one child your current view, and the dynamically you load the second child on the first start. When you load a content view in an Activity, it will be attached to some already created views (some DecorView, a FrameLayout, etc). So you can either re-use the existing FrameLayout, or you can create a new one.
I would vote for the second solution, since it's more stable (I just mentioned the other possibility in case you want to minimize the number of layers).
So, as a first step, wrap your current layout inside a FrameLayout, and give it an id, let's say "#id/root".
Then, in the onCreate method, you can have something like this:
setContentView(R.layout.main);
if (isFirstRun()) {
ViewGroup parent = (ViewGroup)findViewById(R.id.root); // locate the FrameLayout
LayoutInflater li = LayoutInflater.from(this); // get an instance of LayoutInflater
li.inflate(R.layout.overlay, parent);
}
So far you will have the overlay loaded. Now it's up to you to define the overlay.
To make the whitening effect, just set the following attribute on the root view in your overlay.xml layout:
android:background="#40ffffff"
To position the circle, first you need to find it's location. You can use the View.getLocationOnScreen to get the absolute coordinate of the icon (below the circle) on the screen. Then you can have two options:
either create a custom view (for the overlay) and manually draw the circle at the given location
or add the circle using an ImageView and adjust the left and top margins based on the coordinates
Related
Suppose you have a FrameLayout containing 10 LinearLayouts, where only one is visible per time.
Each LinearLayout is a complex view, containing Button, EditText, TextView, etc.
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="#+id/alice
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="visible">
<!-- complex stuff -->
</LinearLayout>
<!-- many more linear layouts... -->
<LinearLayout
android:id="#+id/juliett
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone">
<!-- last complex stuff -->
</LinearLayout>
</FrameLayout>
Thus:
Changing the LinearLayout visibility, in order to show another item, would be a huge performance issue?
Given it is an issue, why using ViewFlipper does not slow down the app performance?
It's bad practice because the code easily become a mess. Ignoring that and focusing only on performance, when you set the visibility to GONE, the view isn't measured (it's different from INVISIBLE). The view occupies a little bit of memory, though. Depending on what you're doing, consider using ViewGroup.removeView().
It's hard to say without a benchmark, but theoretically it shouldn't have performance issues.
This is not a good way to implement because each time you need to show another view, other views must be gone. So that, you are going to write duplicated lines of codes for it. Viewswitcher is better choice. So what about performance then? View switcher is going to measure all children views which make only draw inside of itself. This trick makes view switcher faster because it does not need to recalculate dimensions for itself unless you disable it to use heterogeneous children views.
İf your views are homogeneous, the best way is implement a custom view and giving a class to changing state. For example, you set Alice object to your custom view to show Alice's properties and changing it programmaticly up to your business logic.
Good luck
Emre
Seriously, you need to consider fragment for above situation.
why to inflate un-necessary views.
Just to be clear, we're talking about an XML rotated view here, not the effects of rotating the device. I have a SlidingDrawer that contains a ListFragment. The ListFragment implements the Filterable interface so that users can search its contents by providing a string input through an EditText.
The relevant layout is included below. Because the SlidingDrawer class was deprecated in API 17, the source code was copied over an accessed via a local class. That's why the name of that view looks like a custom class when really it's not.
<com.example.echo.views.SlidingDrawer
android:id="#+id/left_sliding_drawer"
android:layout_height="match_parent"
android:layout_width="wrap_content"
android:handle="#+id/left_handle"
android:orientation="horizontal"
android:content="#+id/people_fragment_container"
android:rotation="180">
<LinearLayout
android:id="#id/left_handle"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:id="#+id/people_tab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/people_map_tab_grey"
android:rotation="180"
android:contentDescription="#string/people_tab"/>
</LinearLayout>
<FrameLayout
android:id="#+id/people_fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</com.example.echo.views.SlidingDrawer>
What happens is, when the users provides input and filters the list such that there are no matching results, i.e., the ListView is empty and size is 0, the entire SlidingDrawer disappears.
Some things I've noticed in trying to fix this:
I am pretty sure this is related to displaying the empty view and/or whatever layout change occurs when it is displayed. If I simply do not set an empty view for the ListFragment the issue does not occur.
I am also pretty sure the effects are related to the fact that the SlidingDrawer is being rotated by 180 degrees since, if I remove the rotation attribute, the issue also does not occur. However, because SlidingDrawer in its default state only opened right to left, this drawer applies the XML attribute android:rotation="180" to flip the view so that it can be opened left to right. This must remain since there is other stuff on the right side of the screen that cannot be moved.
I'm not sure what is making the view disappear or where to start fixing it. I've trying fixing the child views' sizes by overriding onMeasure, onSizeChanged, and onLayout but cannot find anything that solves the issue.
Any ideas are appreciated.
the xml file:
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:id="#+id/singleProp"
android:scrollbarAlwaysDrawVerticalTrack="true"
android:visibility="gone">
<ImageView
android:layout_width="200dp"
android:layout_height="200dp"
android:id="#+id/propertyImg"/>
<ListView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/propertyData"
android:layout_below="#id/propertyImg">
</ListView>
</RelativeLayout>
With the above codes, the image will be fixed at top-center position. With CSS terms in html, the style of that image view is style="position:fixed" but what I want is style="position:relative".
For example,
I hope the picture can illustrate the idea.
May I know how I should modify my codes?
Let me elaborate a bit more on mark.zhai`s answer, since it's the only one that I find to be the proper approach.
First of all I wanna point out that you should think about implementing your list with a RecyclerView instead of ListView (right now it's generally favoured to use a RecyclerView; ListView is getting kinda deprecated)...
If you want to be sure that your ImageView works nicely (scroll-wise) with your list (without too much "side-work" on scroll integration), you should implement it as a first item of your list. If you stick with your ListView you can use the header function of it and add your ImageView with ListView's method addHeaderView. If you decide to move to a RecyclerView (which I think you should), you can accomplish that in a bit more difficult manner (more on that for example here).
why don't u make the imageview an item of the listview
For this you need to create a custom listview which having the first item as a image view and later having all your list items. Probably you can control this in your adapter getview method by the use of position(int)
For example if Position is equal to '0' show only image view and if position is not equal to '0' show your rest elements by using Visibility
Note: here their might be a chance of performance issues as it is loading the unnecessary views every time
To achieve this, you need to scrolling the complete layout. In general case, when you fling on a list view, only the item within the list view moves.
Check this link.
I'm not entirely sure what you're asking, as I don't know a lot about CSS, but you can check out this link which describes aligning elements within a Relative Layout.
You might want to try adding alignParentLeft or alignParentRight.
Remember margins are external to the object and padding is internal. For example to move the image 20dp from the left you would:
<ImageView
android:layout_alignParentLeft="true"
android:layout_marginLeft="20dp"
android:layout_width="200dp"
android:layout_height="200dp"
android:id="#+id/propertyImg"/>
Here are some useful links about mastering Relative Layouts:
Relative Layout Params
Moving Elements Around in a Relative Layout Tutorial
Another RelativeLayout Example
Margins and Padding
Why don't you use layout_below to take your layout below whatever you want, and use layout_gravity to set it's gravity. You can check these Link to get you better understand, it will help you in these problem.
I've done my searches extensively for sure, but I haven't come across exactly what I'm looking for. As such, I haven't any code to show for what I want to do. I want to know if it's possible, first of all, and then get a lead on how to implement such an action.
To keep my app simple, I'd really like to avoid starting a new activity, which seems to be involved in many of the "solutions" that I've seen.
My setup isn't anything special, just a layout with some textviews, buttons, and an image that's about as large as the screen.
I want the user to be able to click the image, and the image will "zoom" or "enlarge" to about 4-5x the size, obviously much of the image will then be off screen. Then, the user should be able to drag the image around to view the entire image as they wish. When they're done looking at the image, they should be able to click to go back to the original size.
I'm sure this will warrant a separate image for each size (one for the original, and a larger more detailed image for the enlarged version). Though, the simpler the better. If I can maintain one larger detailed image and scale it down for the standard view before it's clicked, that'd be great.
I'm assuming they'll be a click listener on the image, but I'm not sure how to do what I want without starting a new activity entirely, then upon clicking again, going back to the original activity. Can it be done in the same activity?
Thanks in advance.
EDIT:
I just had an idea. I could have the larger image in a relative view and make it invisible/gone, then make it visible upon click of the original/main image. Clicking the large image will make itself invisible/gone again. But, assuming this works, I do'nt konw how to set the action of dragging it around and boundaries to make sure you can't drag it outside of the screen entirely.
i have use this library in my project for Zooming images and its very simple to use its helps you ...
https://github.com/chrisbanes/PhotoView
JAVA:
PhotoView mImageView;
PhotoViewAttacher mAttacher;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Any implementation of ImageView can be used!
mImageView = (PhotoView) findViewById(R.id.iv_photo);
// Set the Drawable displayed
Drawable bitmap = getResources().getDrawable(R.drawable.wallpaper);
mImageView.setImageDrawable(bitmap);
// Attach a PhotoViewAttacher, which takes care of all of the zooming functionality.
mAttacher = new PhotoViewAttacher(mImageView);
}
// If you later call mImageView.setImageDrawable/setImageBitmap/setImageResource/etc then you just need to call
attacher.update();
XML:
<uk.co.senab.photoview.PhotoView
android:id="#+id/iv_photo"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="20dp" />
In hopes that this helps someone else and that my solution will suffice in fixing someone else's issue, I'm going to answer my own question with what I found to be a good fix.
To keep it as simple as possible (as it seems that implementing such a feature requires more extensive work that I feel should be necessary), I used the method of toggling hidden/invisible views.
<FrameLayout>
<!--Main Activity-->
<LinearLayout>
<!--Primary Image-->
<ImageView
android:onClick="makeZoomVisible"/>
</LinearLayout>
<!--ScrollView Holder for Enlarged Image-->
<HorizontalScrollView
android:visibility="gone">
<!--Enlarged Image-->
<ImageView
android:onClick="makeZoomInvisible"/>
</HorizontalScrollView>
</FrameLayout>
The base layout is a Frame layout, which allows me to place the Enlarged Image holder (horizontal scroll view) on top of everything else since it comes after the main activity view (linear layout).
Once the primary image is clicked, it calls the method "makeZoomVisible", which as you may guess, toggles the visibility for the horizontal scroll view which holds the enlarged image. The image is scaled up to as large as the height of the screen allows. This works for me because my app is portrait only, and allows the image to scale up approximately 4x the size (a 2x2 of the original image size, just for comparison). Since the image maxes out at the height of the screen, there's no need to scroll/drag up and down. But the horizontal scroll allows the image to be moved side to side to view the whole image.
Clicking the enlarged image calls the method "makeZoomInvisible" which toggles its own visibility, clearing it away and allowing the user to see the main layout of the activity again.
This is the best option for me as a new Android app developer because of its simplicity. To refrain from switching activities, saving/pausing the current activity, implementing 3rd party libraries to include a horizonal+vertical scroll, or pinch zoom and drag features I'm able to achieve what I need for my app.
Hopefully this helps someone else out that may be looking for a simple solution.
I know you decided to implement simple transition yourself without using 3rd party libs. But if someone else is looking for more complex solution, I can suggest to try this library, it allows zooming from i.e. RecyclerView items to ViewPager with animation and includes zoom/pan/rotation features as well.
(Note, I'm the developer of this library)
Simple usage example:
Add regular ImageView and GestureImageView into layout:
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="#+id/image_small"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<com.alexvasilkov.gestures.views.GestureImageView
android:id="#+id/image_full"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
Set same image into both views:
smallImage.setImageDrawable(...);
fullImage.setImageDrawable(...);
Start animation:
fullImage.getPositionAnimator().enter(smallImage, true);
For more info see documentation and sample project.
A great way to do this would be to use a custom ImageView to handle the zooming and dragging of the image that way you can keep it in the same layout without having to start a new activity.
You should check out the TouchImageView library. It contains a custom ImageView that allows pinch zoom, double tap to zoom, dragging, and the ability to manually set the zoom of the image.
If don't want to include the full library a simple way to add this functionality would be to copy the TouchImageView java class into a package in your app (eg com.myapp.views).
Then in your xml layout instead of using:
<ImageView
android:id="#+id/image_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/my_image" />
Change your image to use the path of the custom view class:
<com.myapp.views.TouchImageView
android:id="#+id/image_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/my_image" />
I'm trying to work out how to create the layout for a gridview for my game. I have a gridview which will be the level selector. At the moment I have each gridview item as a TextView, just showing the Level Number (1, 2, 3, etc).
I would like to add 3 imageviews over the top of the textview and be able to manipulate the image shown in the views. The 3 image views are stars, showing what difficulty the level was completed on.
I figure I need to write my own Adapter and inflate the XML layout when creating the views for the grid items but I'm stuck with how to create the actual layout for this, the overlapping part has me scratching my head?
Here's a mockup of what I've tried to describe, and what I want to create:
PS. I know I could use 4 images and set the textview background to one of those images but I wondered if there was a more technical way of creating the layout.
I would use a relative view!
The basics would be, define your button background Bitmap/Drawable with the #1 on it, and then, for each button, have a layout with the copper, silver and gold stars. You can use android:layout_alignParentLeft="true" and android:layout_alignParentBottom="true" on the Copper start and base the other alignments off of that one. Then you just set the stars drawable based on if the star is toggled on or of.
I'm going to use rough psuedo code here:
<RelativeLayout android:id="button1">
<ImageView android:id="copper_star" android:layout_alignParentLeft="true" android:layout_alignParentBottom="true" />
<ImageView android:id="silver_star" android:layout_alignParentBottom="true" android:layout_rightOf="#id/copper_star"/>
...etc...
</RelativeLayout>
Once you've got it looking the way you want, you can see this discussion by Mark Murphy. He explains how to set the properties of a button to do what you'd like.
I went with the un-technical 4 images in the end, it was simple and easy and there aren't any issues scrolling through the grid so it's all good.