I'm working on an extension of BaseExpandableListAdapter, and have the following implementation of getChildView():
public View getChildView(int groupPosition, int childPosition,
boolean isLastChild, View convertView, ViewGroup parent)
{
AbsListView.LayoutParams lp = new AbsListView.LayoutParams
(ViewGroup.LayoutParams.FILL_PARENT, 48);
RelativeLayout layout = new RelativeLayout(myExpandableListActivity.this);
layout.setLayoutParams(lp);
TextView name = new TextView(myExpandableListActivity.this);
name.setText("testing...");
layout.addView(name);
return layout;
}
This code is working, and when I run the application, expand a group and click on a child, the parent application is able to detect onChildClick() correctly.
However, I notice that the onChildClick() does not work anymore if I don't call the setLayoutParms(). My question is, what is happening when I assign AbsListView.LayoutParams to the child view being returned? Why is this required to have my onChildClick() respond in the parent application?
Thanks in advance!
After playing with other parts of the code some more, it looks like leaving out setLayoutParms() was not what was causing my onChildClick() to not work. I was also using a layout inflater to set up my RelativeLayout, which included a CheckBox. Turns out it was the CheckBox that was causing the child to be unclickable, something that I'll have to look into further.
RelativeLayout spellLayout = (RelativeLayout)
getLayoutInflater().inflate(R.layout.testLayout, null);
Thanks for reading!
Related
Background:
It's the classic problem of adding a view and moving it outside parent when it gets clipped. My hierarchy is as follows:
View(any type) -> added to a RelativeLayout -> son of a Linear Layout -> which is added to an Activity using addContentView(...)
I have programmatically added the view into view hierarchy and then moved a little outside parent rect (I tried setTranslationY(-200f), setY(), TranslationAnimation, ..).
The Problem:
The view is partially clipped.
Additional information:
I'm sure the view is of correct size, as the transparent/clipped part can be seen in Layout Inspector as a transparent frame.
The original view added is being cut regardless of which view type it is (RelativeLayout, LinearLayout, a custom Canvas view, a View view.
The parent view is added to an Activity using
mActivity.addContentView(MyLinearLayout, getLayoutParams());
The layout params given are with exact dimensions, something like 500, 500.
I've tried running a function after adding the view that goes through the view and all its parents and disables clipping. Also invalidates all views along the way.
private void setAllParentsClip(View v, boolean enabled) {
while (v.getParent() != null && v.getParent() instanceof ViewGroup) {
ViewGroup viewGroup = (ViewGroup) v.getParent();
viewGroup.setClipChildren(enabled);
viewGroup.setClipToPadding(enabled);
v = viewGroup;
v.invalidate();
} }
I usually prefer to work with classes instead of XML.
Now this is the ordinary way of creating a scene:
TransitionInflater inflater = TransitionInflater.from(this);
ViewGroup mSceneRoot = (ViewGroup) findViewById(R.id.sceneRoot);
Scene mScene2 = Scene.getSceneForLayout(mSceneRoot, R.layout.transition_event,this);
TransitionManager mTransitionManager = inflater.inflateTransitionManager(R.anim.transitions_mgr, mSceneRoot);
mTransitionManager.transitionTo(mScene2);
Pretty neat. Since the R.layout.transition_event is only a TextView, it creates the following layouts. LinearLayout is the root.
For making things happen programmatically we can use the Scene(ViewGroup sceneRoot, ViewGroup layout) constructor instead of Scene.getSceneForLayout(..).
My problem is the ViewGroup layout parameter. Since I want to have only one textview, if I create a FrameLayout and add the textview this will create an extra view as the above screenshot which is not the same.
I either need something like <merge/> but programmatically or "convert" TextView into a ViewGroup.
Here is my best try so far:
# I try to do the equivalent of .getSceneForLayout() here
ViewGroup vg = new ViewGroup(MainActivity.this) {
#Override
protected void onLayout(boolean b, int i, int i2, int i3, int i4) {
}
};
TextView tv = new TextView(MainActivity.this);
tv.setText("YOLO!");
vg.addView(tv,0);
mScene2 = new Scene(mSceneRoot, vg);
Which btw produces:
No sure if worths the hustle but I want to figure this out.
I would like to have a ListView in which some items render on the left, and some on the right. I don't really know how to make this happen though. I was thinking of calling setGravity(Gravity.RIGHT) on the View my adapter's getView() method returns, but that method apparently exists only for ViewGroup, which makes me think it would actually change the gravity of the object's contents. It would look something like this:
getView(int position, View toReturn, ViewGroup parent) {
// Holder pattern, *yawn*
if (needsToBeOnRight) {
toReturn.setGravity(Gravity.RIGHT)
// or whatever it is I'm actually supposed to do
}
return toReturn;
}
The View represented by toReturn is expected to be a RelativeLayout, so I supppose in theory I could cast it to one and try the above, but as discussed above, I doubt that will work. How should I proceed?
Turns out I was almost there. In order to make it work, I had to wrap the view I want to right-or-left-orient in a FrameLayout. That would make toReturn in the above code a FrameLayout.
ViewHolder holder = (ViewHolder) toReturn.getTag();
// Get the view's LayoutParams. In this case, since it is wrapped by a FrameLayout,
// that is the type of LayoutParams necessary.
FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) holder.viewThatMightNeedToBeOnRight.getLayoutParams();
// Set gravity to right or left as necessary within the LayoutParams.
if (params != null) {
if (needsToBeOnRight) {
params.gravity = Gravity.RIGHT;
} else {
params.gravity = Gravity.LEFT;
}
// Assign the newly edited LayoutParams to the view.
holder.viewThatMightNeedToBeOnRight.setLayoutParams(params);
}
LayoutParams lay = new LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT);
lay.gravity = Gravity.END;
mListView.setLayoutParams(lay);
Hi I am developing an app in android where I use a subclass that extends BaseExpandableListAdapter. Right now I have problem to combine ImageView and TextView in the list that is showing. Yesterday I found this link on stackoverflow that helped me to make this combination.
Overlay text over imageview in framelayout programmatically - Android
So it works FINE! - until I click on a listItem. The app chrash and the logcat tells me that
"android.widget.RelativeLayout" cannot be cast to android.widget.ImageView. This exception comes the getGroupView() in the class that extends BaseExpandableListAdapter . Why does this happen? (RelativeLayout extends View).
Am I completely on the wrong way when I try to return a RelativeLayout instead of an ImageView?
Here's my code from getGroupView (I'm a bit messy because I am in a teststate) :
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
ImageView row = (ImageView) convertView;
RelativeLayout rLayout = new RelativeLayout(mContext);
LayoutParams rlParams = new LayoutParams(LayoutParams.FILL_PARENT
,LayoutParams.FILL_PARENT);
rLayout.setLayoutParams(rlParams);
if(row == null) {
row = new ImageView(mContext);
}
row.setImageResource(R.drawable.ic_launcher);
row.setScaleType(ImageView.ScaleType.FIT_START);
RelativeLayout.LayoutParams tParams = new RelativeLayout.LayoutParams
(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);
tParams.addRule(RelativeLayout.CENTER_HORIZONTAL, RelativeLayout.TRUE);
tParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, RelativeLayout.TRUE);
TextView text=new TextView(mContext);
text.setText("GOLDEN Gate");
text.setTextColor(Color.WHITE);
text.setTypeface(Typeface.DEFAULT_BOLD);
text.setLayoutParams(tParams);
rLayout.addView(row);
rLayout.addView(text);
return rLayout;
}
The statement ImageView row = (ImageView) convertView; gives the exception because u r trying to convert the RelativeLayout to ImageView.
You must return the convertView in getViewGroup() method but you are returning the RelativeLayout i.e., return rLayout;
Solution :
Add a ImageView and TextView inside a RelativeLayout. Set that layout for ListItem by inflating it inside getView() method and assign the inflated layout to convertView. Return the convertView in getView() method;
I've got and ExpandableList which I assign to an extended BaseExpandableListAdapter. In here, I implement the getChildView method to setup and return a View for each child:
public View getChildView(int groupIndex, int childIndex, boolean isLastChild, View convertView, ViewGroup parent) {
LinearLayout layout;
if (convertView == null) {
layout = (LinearLayout) LayoutInflater.from(MyApp.getContext()).inflate(R.layout.rooms_room_list_row, parent, false);
} else {
layout = (LinearLayout) convertView;
}
// Do some custom stuff with views on the layout
...
return layout;
}
While debugging, I've noticed that getChildView is executed twice per child. All the values passed in (i.e, groupIndex, childIndex, isLastChild) are the same... so in group 3, if I've got two children, I'll see:
groupIndex = 3, childIndex = 0
then
groupIndex = 3, childIndex = 1
then it repeats:
groupIndex = 3, childIndex = 0
and finally:
groupIndex = 3, childIndex = 1
My view appears fine, i.e, there are only two children listed for the group, but why is it doing all the extra work?
UPDATE & ANSWER
It seems that if the the listview is set to a height of wrap_content then the getChildView will be called twice per child. Changing the height to fill_parent seems to fix this behavior.
As I mentioned in your other question, the ListView calls getView() to get the dimensions (width and height) of some items first, then calls the getView() again to actually render the items. Check this video out, it's "required reading" for Android. The bit that deals with your question is at minute 41:30.