Android - Add Custom View to ListView - java

I have a ListView, and I have a custom View, PostView.
How would I go about creating a new PostView(), and adding it to the ListView via .addFooterView(), but still being able to access the object representation of the PostView.
Right now I'm trying:
// the footer
p = new PostView( this );
p.setTargetUri( C.API_CONTENT );
p.setRenderMode( PostView.MODE_TEXT | PostView.MODE_IMAGE );
commentListView.addFooterView( p );
But that is failing, when I try to access the should have been inflated XML components.
Mainly:
public void setRenderMode( int renderMode )
{
this.renderMode = renderMode;
// fails
this.postImagePreview = (ImageView)findViewById( R.id.new_post_image_preview );
}
Am I going about this wrong? I have an onFinishInflate() defined, but maybe I'm prematurely accessing the Views?

Why not hang on to the instance in a member variable instead of calling findViewById later?

Is your setRenderMode within PostView or the Activity that uses PostView?
If it is in the activity, you should be doing:
this.postImagePreview = (ImageView)p.findViewById( R.id.new_post_image_preview );
with p being a reference to your PostView that you have created.

The solution for me was to just have a super custom List Adapter, that was capable of returning different types of views, and manually adding a header and footer view around the generated list content.

Related

Inflating views in for loop with different identity?

I am inflating layout in view in a for loop and then adding views in Array like:
ArrayList<View> views = new ArrayList();
for (Result datalist : arraylist){
View view = layoutinflater.inflate(R.layout.viewlayout, null);
/*View modification code here....
.............
.............
.............*/
views.add(view);
};
The problem is when i get views from arraylist even by index like views.get(i) it returning only last view. I want to get all views to be able to work on all views.
Here is the code where i am getting views from arrays.
for (View v : views) {
// if (insertPoint != null) {
// if (views != null) {
// if (rel_leftright != null) {
Rect scrollBounds = new Rect();
insertPoint.getHitRect(scrollBounds);
if (v.getLocalVisibleRect(scrollBounds)) {
rel_leftright.setVisibility(GONE);
} else {
rel_leftright.setVisibility(VISIBLE);
}
// }
// }
// }
}
But this code returning only working on last view in array and i need to act on all views.
Please Help me to get out of this. Thanks!!!
First I am missing something:
- Why are you trying to work with the views (/*View modification code here.... ) before you have created all of them? First craete them in the loop and the iterate over views Array and there call the modification code.
- Are you sure you don't want to pass a parent?
View view = layoutinflater.inflate(R.layout.viewlayout, null);
Even if you don't want to be attached you can call:
View view = layoutinflater.inflate(R.layout.viewlayout, parent, false);
And in general it is not possible to fill ArrayList with values and not to find them... Please log the size of datalist, then the size of views. The most probably should match.
And also please note that by the line: /*View modification code here.... not all views are created. You first need to finish the loop.

How to extract the text from Views in AccessibilityDelegate's AccessibilityNodeInfo?

I am trying to get TalkBack to say what is in the text that is inside the host View, along with " is cool" afterwards.
To do this, I am setting an accessibility delegate on a linear layout, but the info parameter's text and contentDescription properties are always null. i.e. info.getText() and info.getContentDescription() are always returning null. I cannot seem to extract the text from the nested TextViews.
The host parameter is thus a linear layout, which contains another nested linear layout inside of it. This nested linear layout in turn contains more nested layouts and text views as their children. (I am targeting API 21+)
linearLayout.setAccessibilityDelegate(new View.AccessibilityDelegate()
{
#Override
public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info)
{
super.onInitializeAccessibilityNodeInfo(host, info);
String newWordsToSay = info.getText() + " is cool"
//info.getText() CRASHES due to null pointer exception
info.setContentDescription(info.setText(newWordsToSay));
}
});
EDIT: On checking the host param, all of the expected nested TextViews are there, with their respective text fields. The problem is, I cannot seem to extract the text from them.
Any help would be appreciated.
It looks like you have to iterate over the children.
You can collect the children relevant for accessibility using View::addChildrenForAccessibility(ArrayList<View> list) method, it fills the passed list. Then you can concatenate their texts:
super.onInitializeAccessibilityNodeInfo(host, info);
ArrayList<View> childrenViews = new ArrayList<>();
host.addChildrenForAccessibility(childrenViews);
StringBuilder text = new StringBuilder();
for (View view : childrenViews) {
if (view instanceof TextView) {
text.append(((TextView)view).getText());
}
}
text.append(" is awesome");
info.setContentDescription(text.toString());

ListView OnLongClick strange behaviour

I have a ListView within my project. It has many elements, and it uses a custom adapter, since its populated dynamically from a rails server.
I want to change the content of a ListItem when the item is longpressed. In order to achieve this, I have 2 layouts inside the ListItem, with one visible and one hidden.
The issue is that when I longpress an item, the layout changes (As expected), but other ListItems are also affected, and changed in the same way. This appear to occur once for every 5 items, and I cant figure out why.
This is the LongClickListener I'm using, it is located inside de GetView method on the custom adapter:
View v = convertView;
if (v == null){
LayoutInflater vi =
(LayoutInflater)getActivity().getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.list_item, null);
}
final LinearLayout placeInfo =
(LinearLayout) v.findViewById(R.id.list_item_info);
final RelativeLayout placeBrief =
(RelativeLayout)v.findViewById(R.id.list_item_brief);
v.setOnLongClickListener(new OnLongClickListener(){
#Override public boolean onLongClick(View v) {
placeInfo.setVisibility(View.GONE);
placeBrief.setVisibility(View.VISIBLE);
return false;
}});
I would appreciate any help, many thanks in advance.
ListViews recycle Views, so you only have a few views for all of your items. You're directly changing one of these view instances to switch between the info|brief. What you need is to save the status of the info|brief flag for the affected position somewhere else (e.g. a list of positions that should be "briefs" in the adapter). That way when you come back into getView() you can display the right one.

get the View at the position X of a ListView

How can I retrieve the View at the position X in a ListView? I dont want to inflate a new one, just retrieve the cell visible in the screen for change some parameters programmatically
Since views in ListView are re-used/re-cycled. There is no direct way of getting a view reference from the ListView.
If you want to access a view you need to extend ArrayAdapter and then override getView. There you should call the super.getView and write your own custom code.
If we you really need to control more than try extending BaseAdapter or CursorAdapter.
Found a dirty solution:
You should be able of identify each row generated. For example adding a TextView with visibility=gone and writing a unique value there when generating (or recycling the row)
In the listactivity call to getListView.setSelection(position) to the desired cell
Survey the listview list for the row (until displayed)
lv=getListView();
for (int i=0;i <lv.getChildCount();i++){
if (((TextView)lv.findViewById(R.id.my_hidden_textview)).getText.equals(mykey)){
// view found
} else {
// schedule another survey "soon"
}
}
For the schedule you can use something like:
final int RETRY_DELAY=100;
new Handler(){
public void handleMessage(Message msg){
if (msg.what<0) return; //something went wrong and retries expired
lv=getListView();
for (int i=0;i <lv.getChildCount();i++){
if (((TextView)lv.findViewById(R.id.my_hidden_textview)).getText.equals(mykey)){
//result = lv.findViewById(R.id.my_hidden_textview);
} else {
this.sendEmptyMessageDelayed(msg.what-1,RETRY_DELAY);
}
}
}
}.sendEmptyMessageDelayed(10,RETRY_DELAY);
As I said is a very ugly solution but it works
I didn't clearly understand your problem. But to what I've understood I would suggest you use a frame layout within a linear layout. You can use another frame layout to do your manipulations.

Find a view by its type (class) having an Activity instance

package net.example.view;
class StatusBar extends View { ... }
I use it in my layout as following:
<net.example.view.StatusBar .../>
I must find it by it's type(class), I mean something like:
myActivityInstance.findViewsByClass(StatusBar.class) // returns View[]
Is it possible? If not, what is the better approach to find an element without having to use findViewById()?
Thanks.
If you can't use the id and your content view is some kind of ViewGroup you can iterate over the children.
ViewGroup vg = (ViewGroup) activity.getContentView();
for(int i=0; i<vg.getChildCount(); i++) {
View v = vg.getChildAt(i);
if(v instanceof StatusBar) {
// do something interesting.
}
}
Also if you know the specific index you can call getChildAt(index) directly.
I don't think activity has a method that will return an array of Views to you based on class type. You could create and add them to your layout dynamically if you want to get an array of them without using findViewById() something like this:
mLayout = (LinearLayout)findViewById(R.id.mLayout);
StatusBar[] mBars = new StatusBar[10];
for(int i = 0; i < mViews.length; i++){
mBars[i] = new StatusBar(yourActivity.this);
mLayout.addView(mBars[i]);
}
That would give you an array full of StatusBar objects that have all been added to your layout. (You could make the array of type View if you wanted also).
If you are wanting to define all of your views in XML I don't think there is a way that you can avoid using findViewById() in a loop similar to this to get an array full of references to all of them. For this method you'd probably have to create an array of ints that is the same size that contains all of the resIDs of your views
ids[0] = R.id.mStatusBar1;
ids[1] = R.id.mStatusBar2;
etc.

Categories

Resources