AppCompatButton cannot be cast to android.view.ViewGroup - java

I am trying to loops through table layout to check the button for a condition and then to change them with setText.
The problem I am having is before that I am getting a ClassCastException.
I see that it says I can't cast a Button to a ViewGroup, but I'm not sure why that it is happening, I am not trying to change anything at that point.
I believe this line (69), is the problem, but nty sure why.
View view = ((ViewGroup) ((ViewGroup) tableLayoutChild).getChildAt(i));
Code:
public Button aiPlayerPick() {
Button btn = null;
TableLayout tableLayout = (TableLayout) findViewById(R.id.tableLayout);
for (int rowIndex = 0; rowIndex < tableLayout.getChildCount(); rowIndex++) {
View tableLayoutChild = tableLayout.getChildAt(rowIndex);
if (tableLayoutChild instanceof TableRow) {
for (int i = 0; i < ((ViewGroup) tableLayoutChild).getChildCount(); i++) {
View view = ((ViewGroup) ((ViewGroup) tableLayoutChild).getChildAt(i));
if (view instanceof Button && view.getTag() == aiPickedButton) {
View btn_v = view.findViewWithTag(aiPickedButton);
System.out.println("Button: " + btn_v);
//btn = (Button) findViewById(R.id.btn_v);
break;
} else {
i++;
}
}
}
}
return btn;
}
Error:
Caused by: java.lang.ClassCastException: android.support.v7.widget.AppCompatButton cannot be cast to android.view.ViewGroup
at com.example.richardcurteis.connect3.MainActivity.aiPlayerPick(MainActivity.java:69)
at com.example.richardcurteis.connect3.MainActivity.playerClick(MainActivity.java:49)
at com.example.richardcurteis.connect3.MainActivity.humanPlayerTurn(MainActivity.java:34)
at com.example.richardcurteis.connect3.MainActivity.receiveClick(MainActivity.java:29)
at java.lang.reflect.Method.invoke(Native Method) 
at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:270)

Even though you're storing a variable of type View, using the cast (ViewGroup) forces a cast to happen before being stored. You're taking the child of the TableRow and casting it to ViewGroup, but its parent is actually View so it fails.
You don't need the second cast, since getChildAt() returns View:
View view = ((ViewGroup) tableLayoutChild).getChildAt(i);

Related

Set gravity of view children from loop of constraintlayout

when I access children which are dynamically created as TextView with a loop of a ConstraintLayout, they are returned as View, which don't have setGravity.
Does anyone know a way to set the gravity of these views (gravity for the TextView/child, not the layout)?
for (int i = 0;i < constraintLayout.getChildCount();i++) {
final View child = constraintLayout.getChildAt(i);
Object tag = child.getTag(R.id.tagId);
if(tag != null) {
//child.setGravity(Gravity.START); // Doesn't work...
} else {} }
I didn't see any option for setting Gravity through
ConstraintLayout.LayoutParams or ConstraintSet either.
Also, I tried final TextView child = (TextView) constraintLayout.getChildAt(i);: However, this resulted in a fatal exception: java.lang.ClassCastException: android.widget.ImageView cannot be cast to android.widget.TextView. Note: The children are textviews, not imageviews...
Cast the view to TextView first, then call setGravity.
final View child = constraintLayout.getChildAt(i);
Object tag = child.getTag(R.id.tagId);
if (tag != null) {
if (child instanceof TextView) {
TextView tv = (TextView) child;
tv.setGravity(Gravity.START);
}
} else {}

Only one expandable list view displays at page load

I am using two different ExpandableListViews in my fragment inside a scroll view, one right below the other.
The problem is that only one ExpandableListView heading is displayed when the activity is called. Please refer the image below:
Also, when I click the expandable list view, the list view expands and the other ExpandableListView also displays. Refer the image below:
I want the both the Expandable list views to display when the activity gets called for the first time.
This is my xml:
<ExpandableListView
android:id="#+id/exLInTheMoodFor"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:scrollbars="none"
android:groupIndicator="#null"
android:layout_below="#+id/lblInTheMoodFor"
android:layout_marginTop="10dp"/>
And this is the java code for defining and initializing the Expandable list view and setting height:
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View convertView = inflater.inflate(R.layout.cafes_more_fragment, container, false);
final ExpandListChild1 items = new ExpandListChild1();
exLInTheMoodFor = (ExpandableListView) convertView.findViewById(R.id.exLInTheMoodFor);
ExpListItems = SetStandardGroups();
ExpAdapter = new ExpandListAdapterProduct(activity, ExpListItems);
exLInTheMoodFor.setAdapter(ExpAdapter);
exLInTheMoodFor.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {
#Override
public boolean onGroupClick(ExpandableListView expandableListView, View view, int i, long l) {
setListViewHeight(exLInTheMoodFor, i);
return false;
}
});
return convertView;
}
//for set height show method in expnadable list view
private void setListViewHeight(ExpandableListView listView, int group) {
android.widget.ExpandableListAdapter listAdapter = (android.widget.ExpandableListAdapter) listView.getExpandableListAdapter();
int totalHeight = 0;
int desiredWidth = View.MeasureSpec.makeMeasureSpec(listView.getWidth(),
View.MeasureSpec.EXACTLY);
for (int i = 0; i < listAdapter.getGroupCount(); i++) {
View groupItem = listAdapter.getGroupView(i, false, null, listView);
groupItem.measure(desiredWidth, View.MeasureSpec.UNSPECIFIED);
totalHeight += groupItem.getMeasuredHeight();
if (((listView.isGroupExpanded(i)) && (i != group))
|| ((!listView.isGroupExpanded(i)) && (i == group))) {
for (int j = 0; j < listAdapter.getChildrenCount(i); j++) {
View listItem = listAdapter.getChildView(i, j, false, null,
listView);
listItem.measure(desiredWidth, View.MeasureSpec.UNSPECIFIED);
totalHeight += listItem.getMeasuredHeight();
}
}
}
ViewGroup.LayoutParams params = listView.getLayoutParams();
int height = totalHeight
+ (listView.getDividerHeight() * (listAdapter.getGroupCount() - 1));
if (height < 10)
height = 200;
params.height = height;
listView.setLayoutParams(params);
listView.requestLayout();
}
Expanding all groups in the list
for(int i=0; i < myAdapter.getGroupCount(); i++)
mexpandableListView.expandGroup(i);
if Expanding one item in the list
mexpandableListView.expandGroup(0);
One item Expanding and balance item compressed
mexpandableListView.setOnGroupExpandListener(new ExpandableListView.OnGroupExpandListener() {
#Override
public void onGroupExpand(int i) {
ExpandableAdapter myAdapter= (ExpandableHomeworkAdapter) mexpandableListView.getExpandableListAdapter();
if (myAdapter== null){
return;
}
for (int k=0;k<myAdapter.getGroupCount();k++){
if (k!=i){
mexpandableListView.collapseGroup(k);
}
}
}
});
The problem was using listview/expandablelistview inside scrollview. Generally this combination causes the visibility issue of listview existing inside the scrollview. Full explanation can be found from this answer. This link and this link should also be helpful for solving your problem. I hope this helps.

notifyDataSetChanged() is canceling changing setColor in ListView

as in topic, when I use adapter.notifyDataSetChanged() text color in a cell which i have already changed is seting back to default value. I don't know why it happens im putting here me method for changing color:
for(int l=0;l<list.size();l++){
System.out. println("kolorujemy! "+ list.size() );
LinearLayout root = (LinearLayout) getViewByPosition(l,listView);
((TextView) root.findViewById(R.id.wartosc_calosci)).setTextColor(Color.YELLOW);
I would also add that this part of code is in loop in other thread because the vaules of the cells is updating every 30 seconds. Here is method getViewByPosition:
public View getViewByPosition(int pos, ListView listView) {
final int firstListItemPosition = listView.getFirstVisiblePosition();
final int lastListItemPosition = firstListItemPosition + listView.getChildCount();
if (pos < firstListItemPosition || pos > lastListItemPosition ) {
return listView.getAdapter().getView(pos, null, listView);
} else {
final int childIndex = pos - firstListItemPosition+1;
return listView.getChildAt(childIndex);
}
}
getView:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ListViewHolder listViewHolder;
if(convertView == null){
listViewHolder = new ListViewHolder();
convertView = activity.getLayoutInflater().inflate(R.layout.lista_wlasnych_spolek, null);
listViewHolder.txtFirst = (TextView) convertView.findViewById(R.id.nazwa_spolki);
listViewHolder.txtSecond = (TextView) convertView.findViewById(R.id.wartosc_akt);
listViewHolder.txtThird = (TextView) convertView.findViewById(R.id.wartosc_kupna);
listViewHolder.txtFourth = (TextView) convertView.findViewById(R.id.wartosc_calosci);
convertView.setTag(listViewHolder);
} else {
listViewHolder = (ListViewHolder) convertView.getTag();
}
First of all this line
return listView.getAdapter().getView(pos, null, listView);
makes no sense, because with this call by hand you will internally always create and inflate new row for the list view but this view is never used within your ListView. See that you are always passing second parameter convertView null so internally this method will create new view but this view will be never used inside your ListView.
Tip 1. Don't call getView() method yourself
As you may know ListView stores in memory only as many rows/view as they are visible on the screen when you use ViewHolder pattern properly.
So for now you are setting color for every row that is visible and even those not visible that really not exist in ListView.
Tip 2.
Best way to color or change anything about any of your rows, is to do it just inside getView() method implementation depend on your adapter item state. Don't do it from outside because it looks like some kind of a hack or wrong architecture.

Android TableLayout.addView() does not really work

I'm trying to fill my TableLayout with some views with the method addView.
This is what I try to do:
private void createNewTable(){
tableLayout = (TableLayout) getView().findViewById(R.id.tableLayout1);
for(int i = 0; i < objectList.size(); i++){
if(objectList.get(i).getType() == 0){
tableLayout.addView(createLocationObjectInTable((LocationObject)objectList.get(i)), i);
}
}
}
and the createObjectInList method:
private View createLocationObjectInTable(LocationObject locObject) {
TableRow tr = new TableRow(getActivity());
View v = LayoutInflater.from(getActivity()).inflate(R.layout.view_layout, tr, false);
TextView textViewCityName = (TextView) v.findViewById(R.id.textView_City_Name);
TextView textViewCityProvider = (TextView) v.findViewById(R.id.textView_City_Provider);
textViewCityName.setText(locObject.getTitle());
textViewCityProvider.setText(locObject.getSubTitle());
return v;
}
But the views aren't displayed in the tableLayout. Logcat doesn't give me any error message, and when I try to do stuff after the line
tableLayout.addView(createLocationObjectInTable((LocationObject)objectList.get(i)), i);
nothing happend. The app just do nothing after this line.
Hope anyone can tell me my mistake?
You don't add your view to TableRow, instead you just add view to TableLayout. Try this:
private View createLocationObjectInTable(LocationObject locObject) {
...
textViewCityProvider.setText(locObject.getSubTitle());
tr.addView(v);
return tr;
}

Iterating through viewgroup

Given a new screen in android i would like to iterate through all the viewgroups and views in order to discover all buttons,text fields, spinner etc... is this possible ?
I get the view count and then use that as a
counter to call getChildAt(int index)
This question may have been long answered, but I wrote this recursive function to set onClickListeners for any buttons I find in my layout, but it could be repurposed:
private void recurseViews(ViewGroup v) {
View a;
boolean isgrp = false;
for(int i = 0; i < v.getChildCount(); i++) { //attach listener to all buttons
a = v.getChildAt(i);
if(a instanceof ViewGroup) setcl((ViewGroup) a);
else if(a != null) {
//do stuff with View a
}
}
return;
}
EDIT: Casting a View as ViewGroup does not raise an exception as had I previously thought, so the code is much shorter now
You could use this to get all child views inside a parent layout, returns an array list of views.
public List<View> getAllViews(ViewGroup layout){
List<View> views = new ArrayList<>();
for(int i =0; i< layout.getChildCount(); i++){
views.add(layout.getChildAt(i));
}
return views;
}
if you want to get a specific view you can use this example. It takes all TextView inside a layout.
public List<TextView> getAllTextViews(ViewGroup layout){
List<TextView> views = new ArrayList<>();
for(int i =0; i< layout.getChildCount(); i++){
View v =layout.getChildAt(i);
if(v instanceof TextView){
views.add((TextView)v);
}
}
return views;
}
As long as the object you're trying to get derives from View class, it will work.

Categories

Resources