I am just learning about android development, and I am having some issues with getting this to work.
I have an activity that uses a relatively layout. I need it to have 2 buttons along the bottom, and then right above the bottoms, I want my custom view to take up the rest of the space.
viewer.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/viewerLayout"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<sketchViewer.AnimationPanelView
android:id="#+id/animationView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="#+id/homeFromViewerButton"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true" />
<Button
android:id="#+id/homeFromViewerButton"
android:layout_width="640dp"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:text="Replay" />
<Button
android:id="#+id/replayButton"
android:layout_width="640dp"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:text="Home" />
</RelativeLayout>
The issue I am having is I that when I run my program, I need to pass a number of parameters into my custom view constructor so that my custom view decides what it should draw. So after creating an instance of my custom view (AnimationPanelView), I am not sure how I set this object into the space I provided for the view.
This is my activity class:
Viewer.java
public class Viewer extends Activity {
AnimationPanelView animationPanelView;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_viewer);
animationPanelView = new AnimationPanelView(this, true /*, more parameters here */);
animationPanelView.setBackgroundColor(Color.GREEN);
RelativeLayout v = (RelativeLayout) findViewById(R.id.viewerLayout);
v.addView(animationPanelView);
}
Right now, with my v.addView command, the view takes up the entire page, covering up the buttons at the bottom. Can anyone shed some light on this? I feel like I am close, but I've been playing around with it for a while, and I just seem stuck.
Check out the implementing a custom view section here. You need to override onLayout and onMeasure so you can tell your container how big you are.
You are adding another custom view to your layout instead you should use
animationPanelView = (AnimationPanelView) findViewById(R.id.animationView);
animationPanelView.setBackgroundColor(Color.GREEN);
Related
I'm building a simple Whack a Mole clone and I'm having trouble figuring out how to do my layout. I haven't played with Android dev since Gingerbread was new, and I've never tried to write a game before, so forgive me if these are newb questions but I've been stuck and Googling for hours now and I'm not getting answers.
I've basically got a 3x4 GridLayout, with 12 invisible mole ImageView declared in a layout.xml file, and I'm having trouble figuring out how I can create object references in my code from what I've created in XML so I can make them randomly appear and disappear and handle user touch events.
I'm seeing a lot of info about GridViews and Adapter objects being used to create references from xml and handle touch events, but I'm not sure how to do this using GridLayout. Should I switch to using a GridView in a LinearLayout, or is there some incredibly simple thing that I'm missing?
Also, would it be better practice to implement the onItemClickedListener() in my Activity subclass or my View subclass? I'm a little confused about how my View subclass relates to the XML layout. Maybe I'm just over-complicating this?
Thanks for any help, guys. Here's my layout.xml if that helps.
<?xml version="1.0" encoding="utf-8"?>
<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:columnCount="3"
android:rowCount="4"
android:useDefaultMargins="true"
android:background="#drawable/grass_bg"
android:id="#+id/wam_view_layout">
<ImageView
android:id="#+id/mole1"
android:visibility="invisible"
android:layout_width="120dip"
android:layout_height="140dip"
android:contentDescription="#string/mole_description"
android:layout_gravity="center"
android:scaleType="fitCenter"
android:src="#drawable/mole" />
<ImageView
android:id="#+id/mole2"
android:visibility="invisible"
android:layout_width="120dip"
android:layout_height="140dip"
android:contentDescription="#string/mole_description"
android:layout_gravity="center"
android:scaleType="fitCenter"
android:src="#drawable/mole" />
<!--pattern continues until mole12-->
</GridLayout>
Do something like that in your activity:
private ImageView imageMole1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout);
imageMole1 = (ImageView) findViewById(R.id.mole1);
imageMole1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// handle click here e.g. call a method
// void onMoleClicked(int moleId)
}
});
}
To change the displayed image use e.g.:
imageMole1.setImageResource(R.drawable.mole_gone);
I am placing four image views on a vertical linear layout. I want them to ocuppy the same space, so I assign to each an android:layout_weight="1". I also want them to overlap (that is a design requeriment), so I set a negative margin for each view. The last image I add (#+id/floor_1st) is the last to be added (the one at the bottom), so it stays at the front. However, I want it to be the other way around: I want the first image on layout to be at the front followed by the second and so on (the last image shuld be at the back).
I understand that it is easier to control the order the images are placed using a RelativeLayout, but I do not know how to place the images the way I want using this layout. I have also seen that is possible to use the method bringToFront(), but that just do not let the images to overlap.
So, is there any way to place the images in the order I want using LinearLayout? Or should I use another layout? In this case, how should I place the images?
Here is my xml code
<LinearLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="#+id/floors_container"
android:layout_gravity="center_horizontal"
android:layout_marginTop="#dimen/overview_buttons_top_margin"
android:layout_marginBottom="#dimen/overview_buttons_bottom_margin"
>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/floor_4th"
android:src="#drawable/piso_4"
android:layout_weight="1"
android:layout_gravity="center_horizontal"
android:layout_marginBottom="#dimen/floors_overview_margin_three_quarter"
android:clickable="true" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/floor_3rd"
android:src="#drawable/piso_3"
android:layout_gravity="center_horizontal"
android:layout_weight="1"
android:layout_marginTop="#dimen/floors_overview_margin_quarter"
android:layout_marginBottom="#dimen/floors_overview_margin_half"
android:clickable="true" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/floor_2nd"
android:layout_gravity="center_horizontal"
android:src="#drawable/piso_2"
android:layout_weight="1"
android:layout_marginTop="#dimen/floors_overview_margin_half"
android:layout_marginBottom="#dimen/floors_overview_margin_quarter"
android:clickable="true" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/floor_1st"
android:src="#drawable/piso_1"
android:layout_gravity="center_horizontal"
android:layout_weight="1"
android:layout_marginTop="#dimen/floors_overview_margin_three_quarter"
android:clickable="true" />
</LinearLayout>
Thanks.
If you want to reverse drawing order, you need to subclass the LinearLayout class and override getChildDrawingOrder.
#Override
protected int getChildDrawingOrder(int childCount, int i) {
//The standard implementation just retuns i
return childCount - i - 1;
}
Make sure to enable custom ordering somewhere:
setChildrenDrawingOrderEnabled(true);
For Android from Level 21, you can use view.setZ() http://developer.android.com/reference/android/view/View.html#Drawing
For Android level below 21, I suggest to use either FrameLayout or RelativeLayout combine with bringToFront() and/or negative padding, margin if required. For using of bringToFront() method, refer to this Defining Z order of views of RelativeLayout in Android
For achieving this kind of layout FrameLayout would be your best bet.
This layout is generally used for z-Index based structure(overlapping). Take a look about this class here :- FrameLayout .
And here is one link which shows its use :- Example Given.
You can find other links too demonstrating its use.
Hope it helps,
Thanks.
I'm a novice on the Android platform when it cames to development. However I'm going further from basic Views and I'd like to create something like the following buttons:
This is what I want to achieve. I first tought that a Button with a custom background would have sufficed. However I don't know any way to make that small darker line with the text inside. All of the image reacts like a button and gets highlighted when you touch it.
Can you help me?
If you look at the source code for Apollo you can see ArtistsFragment is not made up of Buttons but rather an inflated RelativeLayout created by a subclass of the SimpleCursorAdapter class.
Since any view can have an OnClickListener you can make any create a layout to look however you want and still have it act like a button:
// Or load it as an item from an existing layout.
View myView = this.getLayoutInflater().inflate(R.layout.anything);
myView.setOnClickListener(new OnClickListener(){
public void onClick(View arg0) {
// Do stuff.
}
});
Every segment with an image could be a Layout with the background set to the appropriate image. Then, you just put the button inside of the layout.
You have to use Framelayout or RelativeLayout. For example:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ImageView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:scaleType="center"
android:src="#drawable/your_drawabele" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="20dip"
android:layout_gravity="center_horizontal|bottom"
android:padding="12dip"
android:background="#AA000000"
android:textColor="#ffffffff"
android:text="your_text" />
</FrameLayout>
I had asked one question about this error before (Android StackOverflowError in ViewGroup.resetResolvedTextDirection), however now I managed to reproduce the error in the emulator and narrowed down the specific place where this problem occurs.
When I'm starting my activity, I have an AsyncTask, which pulls the necessary data from my server and creates all views. Inside the run() method of the AsyncTask, I'm creating a custom view (and adding it to the main view of the activity - but that's not important now):
ListingView listing = new ListingView(MainActivity.this);
ListingView is my custom view class, which extends from LinearLayout. In the constructor of this custom view, I have this code:
public ListingView(Context context)
{
this.context = context;
...
LayoutInflater infl = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View top = infl.inflate(R.layout.listing, this, true);
this.addView(top);
...
LinearLayout lst = (LinearLayout)this.findViewById(R.id.LayoutListingTop);
tblVenues = new ListView(context);
tblVenues.setVisibility(VISIBLE);
tblVenues.setItemsCanFocus(true);
tblVenues.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if(venueListener != null && venues.size() > 0) { venueListener.selected(venues.get(position)); }
}
});
LayoutParams lp = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);
lst.addView(tblVenues, lp); //this line causes the problem
...
}
In this custom view class, tblVenues is declared as
private ListView tblVenues;
And the XML that's being loaded is this:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:id="#+id/LayoutListingTop"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#color/white">
<ImageView android:id="#+id/ImageView01"
android:layout_width="170dp"
android:layout_height="62dp"
android:src="#drawable/ookl_logo"
android:layout_gravity="left"
android:adjustViewBounds="false"
android:scaleType="fitXY">
</ImageView>
<TextView android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:layout_marginBottom="5px"
android:gravity="center"
android:textColor="#color/black"
android:text="#string/love_culture"
android:id="#+id/TextView01"
android:textSize="28dip">
</TextView>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:id="#+id/ButtonBar"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#drawable/buttonbar"
android:paddingLeft="10px"
android:paddingRight="10px"
android:paddingTop="5px"
android:paddingBottom="5px">
<Button android:id="#+id/BtnListVenues"
android:layout_width="wrap_content"
android:layout_height="45dip"
android:background="#null"
android:text="#string/button_venues"
android:drawableTop="#drawable/icon_venues_on"
android:textColor="#color/venue_blue"
android:layout_marginRight="10px"
android:textSize="9dip">
</Button>
<Button android:id="#+id/BtnListEvents"
android:layout_width="wrap_content"
android:layout_height="45dip"
android:background="#null"
android:text="#string/button_events"
android:drawableTop="#drawable/icon_events_off"
android:textColor="#color/white"
android:layout_marginRight="10px"
android:textSize="9dip">
</Button>
<Button android:id="#+id/BtnListTrails"
android:layout_width="wrap_content"
android:layout_height="45dip"
android:background="#null"
android:text="#string/button_trails"
android:drawableTop="#drawable/icon_trails_off"
android:textColor="#color/white"
android:layout_marginRight="10px"
android:textSize="9dip">
</Button>
<Button android:id="#+id/BtnListObjects"
android:layout_width="wrap_content"
android:layout_height="45dip"
android:background="#null"
android:text="#string/button_objects"
android:drawableTop="#drawable/icon_objects_off"
android:textColor="#color/white"
android:layout_marginRight="10px"
android:textSize="9dip">
</Button>
<TextView android:id="#+id/TxtLabelDistance"
android:layout_width="fill_parent"
android:text="#string/label_distance"
android:layout_height="wrap_content"
android:gravity="right|bottom"
android:layout_alignParentBottom="true"
android:textColor="#color/white"
android:layout_marginTop="-17px"
android:textSize="9dip">
</TextView>
</LinearLayout>
</LinearLayout>
This all works perfectly fine on Android form 1.6 up to 3.x, however on Ice Cream Sandwich (4.0) line
lst.addView(tblVenues, lp);
results in StackOverflowError:
java.lang.StackOverflowError
at android.view.ViewGroup.resetResolvedTextDirection(ViewGroup.java:5131)
at android.view.ViewGroup.resetResolvedTextDirection(ViewGroup.java:5131)
at android.view.ViewGroup.resetResolvedTextDirection(ViewGroup.java:5131)
at android.view.ViewGroup.resetResolvedTextDirection(ViewGroup.java:5131)
at android.view.ViewGroup.resetResolvedTextDirection(ViewGroup.java:5131)
at android.view.ViewGroup.resetResolvedTextDirection(ViewGroup.java:5131)
... this line repeats about 200 times or so ...
There's nothing else useful in the LogCat. The whole ListingView is not even added to the main activity view yet, because the error is thrown essentially from its constructor.
I'm a total loss as to what may be the problem. Any help will be greatly appreciated.
[Old question, but I wasn't pleased with the answer, so adding my notes in hope that they're helpful for someone else.]
Aleks -- I agree with the core issue being an Android bug, but tracing into the code (I encountered a similar issue recently) I believe the issue can be prevented by inflating with the attachToRoot parameter set to false. This is because with attacheToRoot==true, the returned view is the 'root' parameter you passed in. In your case that is 'this', which then add a child of the current view (you're adding the object as a child of itself). This seems to confuse android (it really should check for instance equality).
http://developer.android.com/reference/android/view/LayoutInflater.html#inflate(org.xmlpull.v1.XmlPullParser, android.view.ViewGroup, boolean)
"[Returns] The root View of the inflated hierarchy. If root was supplied and attachToRoot is true, this is root; otherwise it is the root of the inflated XML file."
Making this change resolved the issue in my case.
Update: This is actually a bad advice, that I learned using the API through the years. See top voted answer. You must add a parent view in, even if it's hard to obtain. I believe that's because the layout_ parameters in your root element from the inflated XML depend on the parent layout. For example layout_below (or something like this) is available if your element is a child of a RelativeLayout. At least I got related problems when I passed null in.
I was debugging Android itself, because I made the same mistake, and I found the real reason. The real problem lies within these lines:
View top = infl.inflate(R.layout.listing, this, true);
this.addView(top);
As you can see, you pass this as the second parameter of inflate, that already adds the inflated view to this, so when you do this.addView(top), it gets added one more time. You have two options to correct a mistake like this: delete the line this.addView(top), or replace this with null. I haven't tried the second one, but it should work as well, and is probably a better solution, if you want to manipulate the views before adding to the parent after inflation.
The attachToRoot parameter, that BigDSK mentioned might suffice, but I find that passing null, and addViewing after that, or omitting the addView is a more bulletproof solution (IMHO), so I thought I would share.
After banging my head against the wall for quite some time and trying all sorts of different approaches, I believe, this really is a bug in an android, which is exhibited when a View's visibility is explicitly set to VISIBLE but the view itself and the view's parent is not added to the main view.
I finally got around it by adding the ListView to XML and moving the code setVisibility(View.VISIBLE) to after the entire view is added to the main view (i.e. parent hierarchy can be traced from each child all the way to the end).
At least I'm not getting this error any more.
There is something I'm just not getting, and I'm looking for assistance in understanding what is happening here.
I have a custom list adapter (that just extends BaseAdapter) that I have successfully been using to generate and display a list. Now I want to add a static footer to the bottom of my list. After looking at a number of resources (specifically this one) I've come to realize that my reluctance of using XML has to come to an end, and set up the following xml layout in a file called devices_list.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout android:id="#+id/bottom_control_bar"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true">
<ToggleButton android:id="#+id/bottom_control_toggle"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textOff="Filter Favourites OFF"
android:textOn="Filter Favourites ON"/>
</LinearLayout>
<ListView android:id="#android:id/list"
android:layout_width="fill_parent"
android:layout_height="0dip"
android:layout_above="#id/bottom_control_bar">
</ListView>
<TextView android:id="#android:id/empty"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/main_empty_list"
android:layout_above="#id/bottom_control_bar"/>
</RelativeLayout>
After some adjustments to the activity that holds the list, I ran the code. I see my footer, (and also the tab widget which is parent to everything), but the area where the list goes is empty.
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
this.setContentView(R.layout.devices_list);
db = new DbManager(this);
db.open();
AllCur = db.fetchAllDevices();
startManagingCursor(AllCur);
list = new DeviceListAdapter(this, AllCur); //make my custom list adapter
setListAdapter(list);
}
Is there some way to link up the ListView widget declared in my xml with my DeviceListAdapter? It's pretty clear to me now that I'm not entirely sure about how this is all working. Any help in clarification would be much appreciated.
You have both the ListView and the TextView set to android:layout_above="#id/bottom_control_bar", which means the TextView will overlap the ListView. And, you have said that your ListView height is 0dip, which will make for an extremely short list.
I would define the ListView as being above the TextView and anchored to the top of the screen (android:layout_alignParentTop="true").
Is there some way to link up the
ListView widget declared in my xml
with my DeviceListAdapter?
You already are, by calling setListAdapter().