Android setError() message scrolling on top of ActionBar - android

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

Related

Android ExpandableListView item images disappear

I have to display a list of football players in a list. No problem about that, everything works fine but the little flags for the nationality are disappearing while I scroll down my list.
Here is what it should look like : list item player OK
And here is the result I have after some scrolling : list item player NOK
I also have an Image for the portrait of the player and another one to show the shirt which are working fine.
Here is some part of my code (I only put some parts of it to reduce the size and to put away what's working but feel free to ask for more if you need) :
My item list layout (partial layout, you won't get the same result as the image show) :
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="3dp"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:paddingTop="3dp"
android:orientation="horizontal" >
<ImageView
android:id="#+id/portrait"
android:layout_width="32dp"
android:layout_height="32dp"
android:background="#drawable/portrait_default" />
<LinearLayout
android:id="#+id/nationalityLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal" >
<ImageView
android:id="#+id/logoNationality"
android:layout_width="13dp"
android:layout_height="13dp"
android:layout_marginRight="3dp" />
<TextView
android:id="#+id/nationality"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView"
android:textSize="13dp" />
</LinearLayout>
<LinearLayout
android:id="#+id/shirt"
android:layout_width="40dp"
android:layout_height="32dp"
android:gravity="center_horizontal" >
<TextView
android:id="#+id/number"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="5dp" />
</LinearLayout>
</LinearLayout>
I have a holder for my items :
private class ChildViewHolder {
public ImageView portrait;
public ImageView logoNationality;
public TextView nationality;
public LinearLayout nationalityLayout;
public LinearLayout shirt;
public TextView number;
public void reset() {
portrait.setImageBitmap(null);
portrait.setBackgroundResource(R.drawable.portrait_default);
nationalityLayout.setVisibility(View.VISIBLE);
nationality.setText("");
number.setText("");
}
}
And the getChildView from my adapter (with flags being a map filled while putting items in the adapter list and playerShirt a BitmapDrawable loaded before) :
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
ChildViewHolder holder;
if (convertView == null) {
convertView = LayoutInflater.from(context).inflate(R.layout.liste_item, null);
holder = new ChildViewHolder();
holder.portrait = (ImageView) convertView.findViewById(R.id.portrait);
holder.nationalityLayout = (LinearLayout) convertView.findViewById(R.id.nationalityLayout);
holder.logoNationality = (ImageView) convertView.findViewById(R.id.logoNationality);
holder.nationality = (TextView) convertView.findViewById(R.id.nationality);
holder.shirt= (LinearLayout) convertView.findViewById(R.id.shirt);
holder.number = (TextView) convertView.findViewById(R.id.number);
convertView.setTag(holder);
} else {
holder = (ChildViewHolder) convertView.getTag();
holder.reset();
}
FootPlayer player = children.get(groupPosition).get(childPosition);
// Doing nothing with portrait for now
if (player.getNationality() != null) {
holder.nationalityLayout.setVisibility(View.VISIBLE);
holder.nationality.setText(player.getNationality());
if (player.getNatImg() != null) {
holder.logoNationality.setImageDrawable(flags.get(player.getNatImg()));
} else {
holder.logoNationality.setVisibility(View.INVISIBLE);
}
} else {
holder.nationalityLayout.setVisibility(View.GONE);
}
holder.shirt.setBackgroundDrawable(playerShirt);
holder.number.setText(String.valueOf(player.getNumber()));
return convertView;
}
Right now, flags are appearing at the beginning of the list, proving me that the flags map is correctly filled with my images, but while I scroll down they start to disappear randomly and in the end none of them show up anymore.
So important points are :
My flags map is correctly filled with BitmapDrawable (and correct keys)
My playerShirt is also a BitmapDrawable but doesn't disappear as flags do
I already tried to use setBitmapImage instead of setBitmapDrawable to set the flag image (and also set the background as I'm currently doing with the shirt)
I tried with drawable res images and I have the same result
I know that I go through my if condition to show the flag correctly
Any help about this issue would be greatly appreciated.
You are not setting logoNationality visibility back to VISIBLE, as you are doing with nationalityLayout. So I guess once it's gone for the first time, it remains invisible, even if you later reuse the view setting a drawable to it.
Have a look to the fixed code:
if (player.getNationality() != null) {
holder.nationalityLayout.setVisibility(View.VISIBLE); // <- SET VISIBLE, Well done!
holder.nationality.setText(player.getNationality());
holder.logoNationality.setVisibility(View.VISIBLE); // <- Missing line: SET VISIBLE as before.
if (player.getNatImg() != null) {
holder.logoNationality.setImageDrawable(flags.get(player.getNatImg()));
} else {
holder.logoNationality.setVisibility(View.INVISIBLE); // <- OK, no logo, so hide it.
}
} else {
holder.nationalityLayout.setVisibility(View.GONE); // No nationality, hides entire layout.
}

Android screen white components getting black on resume

I am facing EXTREMELY PECULIAR problem with my android application. I see not a single similar solution anywhere, either on google or on SO.
Here is my screenshot of the app:
This is normal expected output. But when I exit the app and resume again from launcher, often(say 2 out of 5 times) I happen to get the white components(list view and EditText) like this:
In this image, I have touched the first element of listview while taking screenshot so that its shown that the listview items are having actual content and not empty.
Here is my layout resource file main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/ll"
android:cacheColorHint="#00000000"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent" android:weightSum="15" android:background="#android:color/white">
<EditText
android:layout_width="match_parent"
android:layout_height="0dp"
android:id="#+id/edittext" android:layout_weight="2" android:background="#ffffff"
android:textColor="#android:color/black" android:gravity="center" android:hint="Enter Your Text Here"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp" android:layout_weight="2"
android:weightSum="12" android:gravity="center">
<Button android:layout_width="0dp"
android:layout_height="match_parent"
android:text="Tweet"
android:id="#+id/tweetbtn"
android:background="#drawable/mybutton"
android:layout_weight="6"/>
<Button
android:layout_width="0dp"
android:layout_height="match_parent"
android:text="Search"
android:background="#drawable/mybutton"
android:id="#+id/searchbtn"
android:layout_weight="6"/>
</LinearLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="0dp"
android:text="Most Frequently Tweeted"
android:id="#+id/listviewlabel" android:layout_weight="1" android:gravity="center" android:background="#adadad"
android:textColor="#android:color/black"/>
<ListView
android:cacheColorHint="#00000000"
android:background="#ffffff"
android:layout_width="match_parent"
android:layout_height="0dp"
android:id="#+id/listView" android:layout_gravity="center_horizontal" android:layout_weight="10"
android:choiceMode="singleChoice"/>
</LinearLayout>
Please someone help me out with this. Atleast help me resolve the white EditText issue first. That will give me alteast a clue to solve the listview issue.
EDIT:
The listview is dynamically populated by elements. Here is my onStart() method:
#Override
public void onStart(){
super.onStart();
handleFrequentMenuSelected();
}
Here is the handleFrequentMenuSelected():
private void handleFrequentMenuSelected() {
if(!isAccountAdded()){
showToast("Add an account first to get started! Goto Menu and select account.");
}else{
List<StatusElement>aList=getStatusElementsFromSQLiteDatabase();
HashMap<String,Integer> hMap=new HashMap<String, Integer>();
for(StatusElement s:aList){
String tokens[]=s.toString().split(" ");
String outText="";
if(tokens.length>1){
if(tokens[0].contains("/")){
String tokens2[]=tokens[0].split("/");
try{
long l=Long.parseLong(tokens2[0]);
for(int i=1;i<tokens.length;i++){
outText=outText+tokens[i]+" ";
}
}catch(Exception e){
outText=s.toString();
}
}else{
try{
long l=Long.parseLong(tokens[0]);
for(int i=1;i<tokens.length;i++){
outText=outText+tokens[i]+" ";
}
}catch(Exception e){
outText=s.toString();
}
}
}else{
outText=s.toString();
}
outText=outText.trim();
if(hMap.containsKey(outText)){
int cnt=hMap.get(outText);
cnt++;
hMap.put(outText,cnt);
}else{
hMap.put(outText,1);
}
}
hMap= (HashMap<String, Integer>) StaticConstants.sortByValue(hMap);
ArrayList<String>tweets=new ArrayList<String>();
ArrayList<Integer>frequencies=new ArrayList<Integer>();
ArrayAdapter<String>adapter;
int count=0;
for(String s:hMap.keySet()){
tweets.add(s);
frequencies.add(hMap.get(s));
count++;
if(count==50)
break;
}
adapter=new MyCustomFrequentArrayAdapter(this,tweets,frequencies);
listView.setAdapter(adapter);
listViewLabel.setText("Most Frequent Tweets");
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, final View view,
int position, long id) {
final String item = (String) parent.getItemAtPosition(position);
editText.setText(System.currentTimeMillis()+" "+item);
}
});
}
}
Here is my MyCustomFrequentArrayAdapter:
class MyCustomFrequentArrayAdapter extends ArrayAdapter<String> {
private final Context context;
private final ArrayList<String> values;
private final ArrayList<Integer>frequencies;
public MyCustomFrequentArrayAdapter(Context context, ArrayList<String> values,ArrayList<Integer>frequencies) {
super(context, R.layout.customlistview, values);
this.context = context;
this.values = values;
this.frequencies=frequencies;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View rowView = inflater.inflate(R.layout.customlistview, parent, false);
TextView textView1 = (TextView) rowView.findViewById(R.id.firstLine);
TextView textView2 = (TextView) rowView.findViewById(R.id.secondLine);
Log.d("Position",""+position);
//Extracting first six words
String s=values.get(position);
String tokens[]=s.split(" ");
String dispText="";
if(tokens.length>6){
for(int i=0;i<6;i++){
dispText=dispText+tokens[i]+" ";
}
}else{
dispText=s;
}
textView2.setText(dispText);
textView1.setText("Frequency:"+frequencies.get(position));
return rowView;
}
}
Referencing a blog post by Romain Guy - Why Is My List Black
ListView has top and bottom fading edges to indicate it is scrollable.
Creating the fading edge has performance issues so ListView has an optimization to improve performance. Unfortunately the optimization causes problems if the background of the ListView is set to something other than the default.
The optimization can be disabled by setting android:cacheColorHint="#00000000" as you are doing BUT quoting from the blog post...
To fix this issue, all you have to do is either disable the cache color hint optimization, if you use a non-solid color background, or set the hint to the appropriate solid color value.
In other words using android:cacheColorHint="#00000000" should only be used for a "non-solid color" (one which is transparent / translucent).
In your case you are using #ffffff which is an RGB value and by default that means its 'A' component (the alpha) will be ff making it fully opaque, i.e., "solid".
So referring to the last part of the above quote...
...set the hint to the appropriate solid color value.
This suggests you should use android:cacheColorHint="#ffffff" to fix the ListView problem.

Android ListView rows in ScrollView not fully displayed - clipped

I encountered a problem when embedding a ListView inside a ScrollView, or at least that's where I guess the problem comes from. The ListView element is a fairly simple one:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/item_root"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/general_background_list_middle"
android:paddingTop="4dp"
android:paddingBottom="4dp"
android:paddingRight="0dp"
android:paddingLeft="0dp">
<ImageView
android:id="#+id/chat_friends_avatar"
android:layout_width="45dp"
android:layout_height="45dp"
android:layout_marginLeft="7dp"
android:layout_marginRight="8dp"
android:paddingRight="0dp"
android:paddingLeft="0dp"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:src="#drawable/friends_icon_avatar_default"/>
<TextView
android:id="#+id/chat_message_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toRightOf="#id/chat_friends_avatar"
android:layout_alignParentTop="true"
android:layout_marginRight="35dp"
android:maxLines="10"
android:textSize="12dp"/>
<TextView
android:id="#+id/chat_friend_name"
android:layout_width="140dp"
android:layout_height="wrap_content"
android:layout_marginTop="3dp"
style="#style/SubText"
android:layout_toRightOf="#id/chat_friends_avatar"
android:layout_below="#id/chat_message_text" />
<TextView
android:id="#+id/chat_message_time"
android:layout_width="80dp"
android:layout_height="wrap_content"
android:layout_marginRight="8dp"
android:layout_marginTop="3dp"
style="#style/SubText"
android:layout_alignParentRight="true"
android:layout_below="#id/chat_message_text" />
</RelativeLayout>
However, when I embed a list of such elements in a ScrollView, in between some other elements, the rows are not fully displayed, they are clipped (see image below) if the text is wrapped. The ListView is instantiated as follows in the ScrollView:
<ListView
android:id="#+id/info_chat_listview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:cacheColorHint="#color/frame_background_color"
android:clickable="false"
android:divider="#null"
android:footerDividersEnabled="false"
android:focusable="false" >
</ListView>
If the height of the ListView is set to "wrap_content" only the first element is shown. That's why I'm using a method to calculate the height of the rows of the list:
private int getCommentsListHeight() {
if (mChatAdapter != null && mChatAdapter.getCount() != 0) {
if (mChatList != null) {// && mCommentsListItemHeight == 0) {
mCommentsListItemHeight = 0;
for (int i = 0; i < mChatAdapter.getCount(); i++) {
// Get view item height
View viewItem = mChatAdapter
.getView(i, new View(OnAirActivity.this), mChatList);
viewItem.measure(0, 0);
Logger.d(LOGTAG, "View " + i + " measured height = " + viewItem.getMeasuredHeight());
mCommentsListItemHeight += viewItem.getMeasuredHeight();
}
}
//return mChatAdapter.getCount() * mCommentsListItemHeight;
return mCommentsListItemHeight;
} else {
return 0;
}
}
Unfortunately, in case when the text inside the TextView is wrapped, even over several lines, the height of the row element returned by the getMeasuredHeight() method is constant. Also the getLineCount() called on the TextView inside the row element returns 1 even if the text is wrapped.
On the other hand, if this ListView is embedded in a LinearLayout, everything works fine and the full list is displayed with no clipping.
Do you have any suggestions as to what might be wrong here? I really don't like the idea of manually measuring the height of the list elements and it apparently doesn't work but why can't android nicely stretch the ListView inside the ScrollView to fit it all in there?
Clipped list:
Use this method created by https://stackoverflow.com/users/205192/dougw
public static void setListViewHeightBasedOnChildren(ListView listView) {
ListAdapter listAdapter = listView.getAdapter();
if (listAdapter == null) {
// pre-condition
return;
}
int totalHeight = 0;
for (int i = 0; i < listAdapter.getCount(); i++) {
View listItem = listAdapter.getView(i, null, listView);
listItem.measure(0, 0);
totalHeight += listItem.getMeasuredHeight();
}
ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
listView.setLayoutParams(params);
}
It's a BAD practice to encapsulate ListView within a ScrollView because ListView itself contains scrolling capabilities. You should implement a solution that does not contain such hierarchy of views and I hope it will do the magic :)
Here resource of main layout with ScrollView:
<ScrollView android:layout_height="fill_parent" android:layout_width="fill_parent">
<LinearLayout android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" android:id="#+id/parentLayout"/>
</ScrollView>
Here the code to insert items:
parentLayout.removeAllViews();
LayoutInflater inflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
for (int i = comments.size() - 1; i >= 0; i--) {
CommentInfo comment = comments.get(i);
View view = inflater.inflate(your_resource_id, null, false);
TextView commentsContent =(TextView)view.findViewById(R.id.commentContent);
if (commentsContent != null) {
String data = String.format("%s (by %s, %s)", comment.getCommentText(), comment.getUserName(),
commentsContent.setTextSize(st.getTextSize());
commentsContent.setText(data);
}
parentLayout.addView(view, 0);
}
I had the same problem in my project.You need to create simple LinearLayout inside ScrollView. After that you need create new View with your listview item xml using LayoutInflater. After creation put all data in new View and add to LinearLayout as child view:
linearLayot.addView(newView, position_you_need).
Hope it would help you!
I took the recommendation of not using a ListView element inside a ScrollView to heart and decided to use a slightly brute force method to achieve what I need. Since there is a constant number of up to five list rows that need to be displayed I removed the ListView instantiation from the xml file and replaced it with five instances of rows:
<include android:id="#+id/info_comment_1" layout="#layout/chat_single_message" />
<include android:id="#+id/info_comment_2" layout="#layout/chat_single_message" />
<include android:id="#+id/info_comment_3" layout="#layout/chat_single_message" />
<include android:id="#+id/info_comment_4" layout="#layout/chat_single_message" />
<include android:id="#+id/info_comment_5" layout="#layout/chat_single_message" />
In the Activity class I declare five placeholders for these views:
private RelativeLayout mChatMessages[] = new RelativeLayout[COMMENTS_NUMBER];
and initialize them with:
mChatMessages[0] = (RelativeLayout) mMoreInfoLayout.findViewById(R.id.info_comment_1);
mChatMessages[1] = (RelativeLayout) mMoreInfoLayout.findViewById(R.id.info_comment_2);
mChatMessages[2] = (RelativeLayout) mMoreInfoLayout.findViewById(R.id.info_comment_3);
mChatMessages[3] = (RelativeLayout) mMoreInfoLayout.findViewById(R.id.info_comment_4);
mChatMessages[4] = (RelativeLayout) mMoreInfoLayout.findViewById(R.id.info_comment_5);
Then, whenever a new message is received I use the ChatAdapter (the same I used for the ListView previously) and call its getView() method:
protected void updateChatMessages() {
int msgCount = mChatAdapter.getCount();
for (int i = 0; i < COMMENTS_NUMBER; i++) {
if (msgCount <= i) {
mChatMessages[i].setVisibility(View.GONE);
} else {
mChatMessages[i] = (RelativeLayout) mChatAdapter.getView(i, mChatMessages[i], null);
mChatMessages[i].setVisibility(View.VISIBLE);
}
}
}
I don't inflate the pariculat views ever again since the only thing that changes is the content of each row, not the layout. This means there is no performance penalty here.
This is basically a manual implementation of a ListView with a limited maximum number of elements. This time, however, ScrollView is able to fit them nicely and nothing gets clipped.
For a dynamic number of rows the approach suggested by Layko could be employed with the views being instantiated programatically and added to the LinearLayout inside the ScrollView.
I can see the ListView is inside a ViewPager; one other simple approach to resolving this issue is to add
app:layout_behavior="#string/appbar_scrolling_view_behavior" to the ViewPager in your layout xml as seen below.
<android.support.v4.view.ViewPager
android:id="#+id/viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"/>
To prevent the same behavior at the bottom of the list, you can also add android:layout_marginBottom="?attr/actionBarSize" to the ViewPager like so
<android.support.v4.view.ViewPager
android:id="#+id/viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
android:layout_marginBottom="?attr/actionBarSize"/>
This is coming late, but I hope it helps any other person.
try it..
after create all view add bellow line for ScrollView location on screen (x,y)
ScrollView scrollView = (ScrollView)findViewById(R.id.scrollView);
scrollView.smoothScrollTo(0,0);// top location zero index
I had a similar problem. I have a
RelativeLayout
listView
includeLayout
where I include some bottom nav beneath the listView with this
<include
android:id="#+id/includeLayout"
layout="#layout/bottom_nav_bar"
and my listView was clipped - not taking the full height available between the header and bottom nav. I tried various xml settings suggested in this and other threads, but what worked for me was to add
android:layout_alignBottom="#+id/includeLayout"
to my listView. That seemed to pull the listView down to the top of the bottom nav, so that the listView is now using the full available height (and it scrolls as needed).
This works for me
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="#dimen/activity_vertical_margin">
<TextView
android:id="#+id/tv_status"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:textSize="17sp"
android:text="#string/text_list_devices" />
<ListView
android:id="#+id/lv_paired"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="#dimen/activity_vertical_margin"
android:cacheColorHint="#00000000"
android:layout_above="#+id/signup_t"
android:layout_below="#id/tv_status"
/>
<Button
android:id="#+id/signup_t"
style="?android:textAppearanceSmall"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:textColor="#android:color/white"
android:layout_alignParentBottom="true"
android:text="Print All Records"
android:typeface="sans"
android:layout_marginLeft="45dp"
android:layout_marginRight="45dp"
android:textSize="24sp"
android:background="#drawable/selector_for_button"
android:textStyle="bold" />
</RelativeLayout>
This is BAD practice. But there are some situations we can not avoid using that. For example dynamic e-commerce layouts we may put multiple lists or recycle views but you don't want to scroll inside a single item height (if accidentally wanted!!). I faced this kind of problem. I fixed using a simple way. I don't tell this is the correct way but it may help some.
!! I used to recycle the view.
(01) Create an Interface to return view height.
public interface AfterViewLoadListener {
void onViewHeightMeasured(int height, String mode);
}
(02) implement with your activity
public class *Activity extends AppCompatActivity implements AfterViewLoadListener{
/** your codes **/
final SimpleListRecycleAdapter order_adapter = new SimpleListRecycleAdapter(this,"ORDER");
}
#Override
public void onViewHeightMeasured(int height, String mode) {
if(mode.equals("ORDER") && height > 0){
recycleView.setMinimumHeight(height);
}
}
(03) inside the recycle view custom adapter
AfterViewLoadListener viewLoadListener = null;
public SimpleListRecycleAdapter(AfterViewLoadListener listener, String mode) {
if(listener instanceof AfterViewLoadListener){
viewLoadListener = listener;
}
this.mode = mode;
}
(04) override the onViewAttachedToWindow method
#Override
public void onViewAttachedToWindow(#NonNull SimpleListViewHolder holder) {
super.onViewAttachedToWindow(holder);
View view = holder.itemView;
view.measure(0, 0);
this.viewMinHeight = view.getMeasuredHeight();
if(!firstFlag){
firstFlag = true;
viewLoadListener.onViewHeightMeasured(this.viewMinHeight*filtered.length(),mode);
}
}
(05) That's it. It worked for me.

ClassNotFoundException android.view.scrollview when Inflating view

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);

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.

Categories

Resources