ClassNotFoundException android.view.scrollview when Inflating view - android

I'm trying to inflate a view containing a scrollview and i get a ClassNotFoundException android.view.scrollview when Inflating view on the following line:
View layout = inflater.inflate(R.layout.news_article, null, true);
I cannot find anything wrong myself and googling the issue didn't help me (unfortunatly).
On the other hand, this is actually also a workaround for something I don't know how to do.
Situation:
I've got a tab layout with 3 tabs. In each tab, I've got a listview containing a news-item. When I click on the news-item, I want the listview layout to be switched with the xml layout i'm now using for the popup (it's kinda cheating, but I don't know how to do it properly). So if anybody has a way to do this instead of using a popup, it will be the best answer for me.
Method where I inflate the layout:
#Override
public void onClick(View v)
{
//setContentView(R.layout.news_article);
final PopupWindow popUp;
LayoutInflater inflater = (LayoutInflater)NewsActivity.this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View layout = inflater.inflate(R.layout.news_article, null, false);
Display display =GetWindowManager().getDefaultDisplay();
int popUpWidth = display.getWidth();
int popUpHeight = display.getHeight();
popUp = new PopupWindow(layout, popUpWidth, popUpHeight, true);
popUp.setOutsideTouchable(true);
popUp.setTouchInterceptor(new OnTouchListener()
{
#Override
public boolean onTouch(View v, MotionEvent event)
{
System.out.println("Touch Intercepted");
if(event.getAction() == MotionEvent.ACTION_OUTSIDE)
{
popUp.dismiss();
}
return false;
}
});
popUp.showAtLocation(getListView(), Gravity.TOP, 0, 75);
}
XML code for the layout:
<?xml version="1.0" encoding="utf-8"?>
<Scrollview
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/news_article_scroll"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#ffffffff">
<ImageView
android:id="#+id/news_article_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:src = "#drawable/ic_launcher"/>
<TextView
android:id="#+id/news_article_header"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20dp"
android:textColor="#000000"
android:layout_toRightOf="#+id/news_article_icon"
android:layout_marginTop="10dp"
android:text="Header" />
<TextView
android:id="#+id/news_article_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#id/news_article_icon"
android:layout_marginTop="10dp"
android:textColor="#000000"
android:text="Text" />
</RelativeLayout>
</Scrollview>
*******EDIT********
Ok, the popup now shows, but I'm not receiving any events from it

I tried it in my code and it works when I change Scrollview to ScrollView in the xml file:
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
</ScrollView>
The xml is correct if you write it with a small 'v' but the inflater does not recognize it and requires a capital 'V'.
You can see that very easily when you put a try catch block around it and check the exception because it says it there.

When you inflate your layout you set no parentView, but you set the flag true
View layout = inflater.inflate(R.layout.news_article, null, true);
Set the flag to false and add the view where you need it.
View layout = inflater.inflate(R.layout.news_article, null, false);
myParentViewGroup.add(layout);

Related

why dynamically set text to TextView not visible in popup window while hard coded is

I am trying to generate popup window containing dynamically generated text. log output clearly shows that the desired text is actually set to textView but I can't understand why it is not showing on the app.
MainActivity.java
#Override
public boolean onOptionsItemSelected(MenuItem item) {
linearLayout = (LinearLayout) findViewById(R.id.main_activity_parent_layout);
int id = item.getItemId();
if(id == R.id.info_button){
layoutInflater = (LayoutInflater) getApplicationContext().getSystemService(LAYOUT_INFLATER_SERVICE);
//Updating a textview in different layout xml from the main activity
LinearLayout vi = (LinearLayout)layoutInflater.inflate(R.layout.activity_info, null);
TextView textView = vi.findViewById(R.id.info);
textView.setText(R.string.main_activity_info);
Log.i("MainActivity",String.valueOf(textView.getText()));
ViewGroup container = (ViewGroup)layoutInflater.inflate(R.layout.activity_info,null);
popupWindow = new PopupWindow(container, WindowManager.LayoutParams.WRAP_CONTENT,WindowManager.LayoutParams.WRAP_CONTENT,true);
popupWindow.setOutsideTouchable(true);
popupWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
//Note showAtLocation method should always in end for proper rendering of poup Window
popupWindow.showAtLocation(linearLayout,Gravity.TOP,0,100);
}
return super.onOptionsItemSelected(item);
}
activity_info.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/info"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#android:color/white"
android:padding="8dp"
android:text="hello"
android:textAppearance="?android:textAppearanceMedium"
android:textColor="#android:color/black"/>
</LinearLayout>
popup window show hello which is hardcoded text.
You are inflating R.layout.activity_info two times and losing the TextView you are changing in the process. Make the following change to keep the first inflation and your modification:
popupWindow = new PopupWindow(vi, WindowManager.LayoutParams.WRAP_CONTENT,WindowManager.LayoutParams.WRAP_CONTENT,true);

Android handling clicks on parentView

Click events handling does not work.
Click handling works with CheckBox and TextView, but doest not work with frameLayout.
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="56dp"
android:background="#drawable/yellow_ripple"
android:clickable="true"
>
<TextView
android:clickable="false"
android:id="#+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"/>
<CheckBox
android:clickable="false"
android:id="#+id/box"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|right"
/>
In create view:
View resultView = LayoutInflater.from(context)
.inflate(R.layout.filter_signle_view, parent, true);
selectedBox = (CheckBox) resultView.findViewById(R.id.box);
title = (TextView) resultView.findViewById(R.id.text);
title.setText(m_filter.getTitle());
selectedBox.setChecked(m_state.isSelected());
selectedBox.setOnCheckedChangeListener((compoundButton, b) ->
m_state.setSelected(b)
);
resultView.setClickable(true);
resultView.setOnClickListener(
view -> m_state.setSelected(!m_state.isSelected())
);
);
return resultView;
I want to handle clicks on FrameLayout. It is not happening.
(I use retrolamda)
You are assigning the listener to the parent of your frame layout.
Please change last parameter of your inflation from true to false. For more - LayoutInflater.inflate(int, ViewGroup, boolean)
View resultView = LayoutInflater.from(context).inflate(R.layout.filter_signle_view, parent, false);
1) Add listener to frame layout. You are missing it and its the most important thing here.
2) Add
android:descendantFocusability="blocksDescendants"
to frame layout in xml. This will prevent child items clicks.
Ok, so after fixing numerous compile errors and other Lint issues, I did run your code (slightly modified). And it worked fine, here's what I have.
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="56dp"
android:background="?attr/selectableItemBackground"
android:clickable="true">
<TextView
android:id="#+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:clickable="false" />
<CheckBox
android:id="#+id/box"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|end"
android:clickable="false" />
</FrameLayout>
And the Java part...
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View resultView = LayoutInflater.from(getActivity()).inflate(R.layout.generator_personalization, container, false);
CheckBox selectedBox = (CheckBox) resultView.findViewById(R.id.box);
TextView title = (TextView) resultView.findViewById(R.id.text);
title.setText("Title!");
selectedBox.setChecked(true);
selectedBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
Toast.makeText(getActivity(), "Changed!", Toast.LENGTH_SHORT).show();
}
});
resultView.setClickable(true);
resultView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(getActivity(), "CLICKED!", Toast.LENGTH_SHORT).show();
}
});
return resultView;
}
So basically, what I think is the biggest problem here is attaching the view to the parent in your inflate statement. Try changing that last parameter to false.
You should also note that setting click listeners from code also sets the clickable attribute when enabled.
Hope this helps!
P.S. Consider changing that layout to something more maintainable - like using a single CheckBox instead of FrameLayout + TextView + CheckBox without text.
When you infilating a layout, you supply this parameters to the inflator service:
public View inflate(int resource, ViewGroup root, boolean attachToRoot)
If you set attachToRoot true then the returned view is the root view that you suppilied.
In your example you set it to true and it is returning the "parent" view.
You then set a click listener to a parent viewgroup, however, the click event will be consumed on the child FrameLayout because you set the clickable to true. In your case this will do nothing because you set the click listener to the wrong view, and another view consumed the click event.
So you should set the attachToRoot to false, and the returned view will be your FrameLayout, and that will fix your problems.

Android setError() message scrolling on top of ActionBar

My issue is that the error message in my EditTexts are scrolling on top of the action bar. Is this an android bug, or am I doing something wrong?
Also this bug happens even when the keyboard is down, it just happens to be up in the screenshots.
Here is what I am talking about: http://imgur.com/fG8bd3E,uFzhOXa#1 <- there are two images
Here is my layout, I add the EditTexts in my code to the kiosk_form_table LinearLayout
<ScrollView
style="#style/DefaultBackground"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="0.6"
android:fadeScrollbars="false"
android:padding="20dp" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingRight="20dp" >
<LinearLayout
android:id="#+id/kiosk_form_table"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" />
<Button
android:id="#+id/kiosk_submit_large"
style="#style/LoginButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:onClick="submit"
android:text="#string/submit" />
</LinearLayout>
</ScrollView>
How I add the EditTexts
kiosk_form.addView(getKioskRow(R.layout.kiosk_text_row, "First Name", true, null));
private View getKioskRow(int layout, String header, boolean required, String buttonName)
{
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(layout, null);
view.setTag(required);
addHeader((TextView) inflater.inflate(R.layout.field_header, null), header);
if (required)
((TextView) view.findViewById(R.id.kiosk_input)).setHint("Required");
if (buttonName != null)
((Button) view.findViewById(R.id.kiosk_input_button)).setText(buttonName);
return view;
}
private void addHeader(TextView view, String header)
{
view.setTag(false);
view.setText(header);
kiosk_form.addView(view);
}
How I set the error
(TextView) view).setError(getString(R.string.error_field_required));
It is Android OS bug.
You can track its progress here
I had the same problem. Solved it like this:
private void processingErrorPopupsWhenScrolling(Rect scrollBounds, TextInputEditText... views) {
boolean isViewInFocus = false;
for (TextInputEditText textInputEditText : views) {
if (textInputEditText.getError() != null) {
if (textInputEditText.getLocalVisibleRect(scrollBounds)) {
textInputEditText.setVisibility(View.VISIBLE);
if (!isViewInFocus) {
textInputEditText.requestFocus();
isViewInFocus = true;
}
} else {
textInputEditText.setVisibility(View.INVISIBLE);
}
}
}
}
// in onCreate(){
Rect scrollBounds = new Rect();
mScrollView.getHitRect(scrollBounds);
mScrollView.getViewTreeObserver().addOnScrollChangedListener(() ->
processingErrorPopupsWhenScrolling(scrollBounds,
mLink,
mTitle,
mPrice)
);}
I resolve similiar problem by setting flag
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
Where do you want to see the error message? If you want it on EditText, set it on editText.
((EditText) findViewByID(R.id.my_edit_text)).setError ...... // and so on
Edit: original answer didn't help.
Here's one possible solution: you can hide the error message when the user is scrolling the view. When the scroll has finished you can re-set the error message and it should appear in the right spot! Here's how you can detect when a scroll finished:
Android: How to detect when a scroll has ended

Click Event on ImageButton not dispatched immediately

I'm having a weird problem, in my rather complex view layout. (I will try to simplify it a bit in my explanation)
Basically I have a ListView, where each item consists of a TextView and an ImageButton. I am able to either click the list item (on the textview), or the button (I set the ImageButton to non-focusable, otherwise it wouldn't work)
Now it seems to work fine, until I open another window and return to the listview.
From that point on, I can click the ImageButton without anything happening (not even the background changes during the click). But when I click on the TextView again, all the click events from the ImageButton are dispatched at once.
Why is that?
EDIT:
The List Item:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="0px"
android:minHeight="40dp"
android:orientation="horizontal"
android:paddingLeft="2px"
android:paddingRight="2px"
>
<TextView
android:id="#+id/text1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Text"
android:textSize="19dp"
android:paddingTop="4px"
android:paddingBottom="4px"
android:layout_gravity="center_vertical"/>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/open_subtree_layout"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_margin="0px"
android:orientation="horizontal"
android:padding="0px">
<View
android:layout_width="1px"
android:layout_height="match_parent"
android:background="#drawable/separator_line" />
<com.treeviewer.leveldisplay.DontPressWithParentImageButton
android:id="#+id/btn_right"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:background="#drawable/list_selector_background"
android:focusable="false"
android:focusableInTouchMode="false"
android:padding="10dp"
android:src="#drawable/arrow_right" />
</LinearLayout>
</LinearLayout>
That's how it is inflated:
[...]
LayoutInflater inflater = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mView = inflater.inflate(R.layout.tree_row, null, false);
TextView textView = (TextView)mView.findViewById(R.id.text1);
LinearLayout nextNodeButtonContainer = (LinearLayout)mView.findViewById(R.id.open_subtree_layout);
if(childCount >= 0) {
titleBuilder.append(" (" + childCount + ")");
nextNodeButtonContainer.setVisibility(View.VISIBLE);
View button = nextNodeButtonContainer.findViewById(R.id.btn_right);
button.setFocusable(false);
button.setFocusableInTouchMode(false);
//button.setClickable(true);
button.setOnClickListener(clickListener);
button.setTag(tagValue);
} else {
nextNodeButtonContainer.setVisibility(View.GONE);
}
textView.setText(titleBuilder);
Let me know, if you need more code.
Ok, I finally solved this problem.
Unfortunately, in my question I didn't provide the necessary information to solve it, as the problem was somewhere I didn't expect it:
I have a ListAdapter where the getView method looks like this:
public View getView(int position, View convertView, ViewGroup parent) {
return mNodes.get(position).getView(mNodeArrowClickListener, position);
}
And the getView method of the nodes (TreeLevelElements) looked like:
public class TreeLevelElement {
private final Context mContext;
private View mView = null;
//[...] other methods
View getView(OnClickListener clickListener, final int tagValue) {
if(mView == null) {
//[...] produce a new View from XML
}
return mView;
}
}
The problem was, that I stored the Views in my elements, so I guess that conflicted somehow with android strategy to reuse old views for new items.
I don't know what exactly happened, but now that I removed mView and create a new one every time, it works.
I will also change it to reuse the convertView instead.

How to use the xml setting in a view of a activity?

I want to show two views in one activity. If I clicked on button in the first view I want to see the second and other way round.
The views should not have the same size as the screen so I want e.g. to center it, like you see in first.xml.
But if I add the views with
addContentView(mFirstView, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
the views are not centered. They are shown at top left.
How can I use the xml settings to e.g. center it?
first.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_height="wrap_content" android:layout_width="wrap_content"
android:background="#drawable/background"
android:layout_gravity="center"
android:minWidth="100dp"
android:minHeight="100dp"
android:paddingBottom="5dp"
>
<LinearLayout android:id="#+id/head"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageButton android:id="#+id/first_button"
android:src="#drawable/show_second"
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#null" />
</LinearLayout>
second.xml same as first.xml but with
<ImageButton android:id="#+id/second_button"
android:src="#drawable/show_first"
... />
ShowMe.java
public class ShowMe extends Activity {
View mFirstView = null;
View mSecondView = null;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initFirstLayout();
initSecondLayout();
showFirst();
}
private void initFirstLayout() {
LayoutInflater inflater = getLayoutInflater();
mFirstView = inflater.inflate(R.layout.first, null);
getWindow().addContentView(mFirstView, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
ImageButton firstButton = (ImageButton)mMaxiView.findViewById(R.id.first_button);
firstButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
ShowMe.this.showSecond();
}
});
}
private void initSecondLayout() {
// like initMaxiLayout()
}
private void showFirst() {
mSecondView.setVisibility(View.INVISIBLE);
mFirstView.setVisibility(View.VISIBLE);
}
private void showSecond() {
mFirstView.setVisibility(View.INVISIBLE);
mSecondView.setVisibility(View.VISIBLE);
}}
Hope someone can help.
Thanks
Why don't you use setContentView(R.layout.yourlayout)? I believe the new LayoutParams you're passing in addContentView() are overriding those you defined in xml.
Moreover, ViewGroup.LayoutParams lacks the layout gravity setting, so you would have to use the right one for the layout you're going to add the view to (I suspect it's a FrameLayout, you can check with Hierarchy Viewer). This is also a general rule to follow. When using methods that take layout resources as arguments this is automatic (they might ask for the intended parent).
With this consideration in mind, you could set your layout params with:
FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(/* wrap wrap */);
lp.setGravity(Gravity.CENTER);
addContentView(mYourView, lp);
But I would recommend setContentView() if you have no particular needs.
EDIT
I mean that you create a layout like:
~~~/res/layout/main.xml~~~
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="....."
android:id="#+id/mainLayout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
then in your onCreate() or init...Layout():
setContentView(R.layout.main);
FrameLayout mainLayout = (FrameLayout)findViewById(R.id.mainLayout);
// this version of inflate() will automatically attach the view to the
// specified viewgroup.
mFirstView = inflater.inflate(R.layout.first, mainLayout, true);
this will keep the layout params from xml, because it knows what kind it needs. See reference.

Categories

Resources