I have a very strange problem in my navigation drawer.
I want to implement the navigation drawer like the one the Google Play Store has.
I've implement my navigation drawer in a base adapter but when I run my app in a emulator everythings looks fine when I open the navigation drawer, but when I click a item suddenly all items are mixed up(only on my android 2.3 device) The other one i;ve tested is a 4.4.2 Android device and everything works fine!
Code
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
LayoutInflater mInflater = (LayoutInflater)
context.getSystemService(ActionBarActivity.LAYOUT_INFLATER_SERVICE);
convertView = mInflater.inflate(R.layout.drawer_list_item, null);
}
if (convertView != null) {
//i//f(!(navDrawerItems.get(position).IsLoaded())) {
//navDrawerItems.get(position).SetLoaded();
ImageView imgIcon = (ImageView) convertView.findViewById(R.id.icon);
TextView txtTitle = (TextView) convertView.findViewById(R.id.title);
TextView txtCount = (TextView) convertView.findViewById(R.id.counter);
if (navDrawerItems.get(position).getIconVisibility()) {
imgIcon.setImageResource(navDrawerItems.get(position).getIcon());
txtTitle.setTextSize(20);
//txtTitle.setMinHeight(20);
LinearLayout.LayoutParams llp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
llp.setMargins(8, 0, 0, 0); // llp.setMargins(left, top, right, bottom);
llp.height = 60;
txtTitle.setLayoutParams(llp);
convertView.setBackgroundResource(R.drawable.nav_little_border);
} else {
imgIcon.setVisibility(View.GONE);
}
txtTitle.setText(navDrawerItems.get(position).getTitle());
// displaying count
// check whether it set visible or not
if (navDrawerItems.get(position).getCounterVisibility()) {
txtCount.setText(navDrawerItems.get(position).getCount());
} else {
// hide the counter view
txtCount.setVisibility(View.GONE);
}
// }
}
I only want to show the icons for the last 2 items like (http://www.androidcentral.com/sites/androidcentral.com/files/styles/large_wm_brw/public/article_images/2014/04/Play-Movies-TV-sidebar.jpg?itok=qLSLoPNp)
Related
Right now I'm working on a launcher app, in which I've made a GridView which fetches all installed apps from the device. But there are only app icons and no app names. And I wanted to put app name below it so I tried to put TextView below my app icon ImageView, but my app crashes. Any ideas how should I fix it? Here's my code: Thank you very much!
public View getView(int position, View convertView, ViewGroup parent) {
ImageView i;
if (convertView == null) {
i = new ImageView(Apps.this);
i.setScaleType(ImageView.ScaleType.FIT_CENTER);
i.setLayoutParams(new GridView.LayoutParams(93, 93));
i.setPadding(15, 15, 15, 15);
} else {
i = (ImageView) convertView;
}
ResolveInfo info = mApps.get(position);
i.setImageDrawable(info.activityInfo.loadIcon(getPackageManager()));
return i;
}
Instead of building a view that contain TextView and ImageView, use CompoundDrawable. You only have to implement one TextView and set it's DrawableTop with the required icon. This will do the job.
From the XML file
<TextView
android:id="#+id/my_textview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawableTop="#drawable/my_icon"
android:gravity="center"
/>
Or you can do it programmatically using the following:
myTextView.setCompoundDrawablesWithIntrinsicBounds(null, topDrawable, null, null);
Simply use a TextView as the image container, by using a compound drawable: http://developer.android.com/reference/android/widget/TextView.html#setCompoundDrawablesWithIntrinsicBounds(int,%20int,%20int,%20int)
So, you'll set 1 View to replace 2 ones, with UI simplification and performance improvements, as side-effects.
A little example:
public View getView(int position, View convertView, ViewGroup parent) {
TextView t;
if (convertView == null) {
t = new TextView(Apps.this);
t.setLayoutParams(new GridView.LayoutParams(93, 93));
t.setPadding(15, 15, 15, 15);
ResolveInfo info = mApps.get(position);
Drawable drw = info.activityInfo.loadIcon(getPackageManager());
t.setCompoundDrawablesWithIntrinsicBounds(null, drw, null, null);
//t.setText("Some Text");
t.setText(info.activityInfo.loadLabel(getPackageManager()).toString());
} else {
t = (TextView) convertView;
}
return t;
}
[EDIT]
Once you return the View (t, the TextView), you can get the drawable by using getCompoundDrawables(): http://developer.android.com/reference/android/widget/TextView.html#getCompoundDrawables()
this is the code in my custom adapter (THE CODE IN BROWN COLOR) when initially list is build proper margin is applied to valid items when i scroll down and again scroll up all the rows in list shifts the margin left by 20 what i'm doing wrong please reply soon
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
final ViewHolder holder;
// getting data
final ViewMovieDetailsModel_ViewComments movies = getItem(position);
if (convertView == null)
{
convertView = View.inflate(context, R.layout.comment_row, null);
holder = new ViewHolder();
//getting handles
holder.comments_linearLayout = (LinearLayout) convertView.findViewById(R.id.comments_linearLayout);
holder.commenter_textView = (TextView) convertView.findViewById(R.id.comment_row_commenter);
holder.commented_on_textView = (TextView) convertView.findViewById(R.id.comment_row_comment_time);
holder.comment_text_textView = (TextView) convertView.findViewById(R.id.comment_row_comment_text);
holder.reply_button = (Button) convertView.findViewById(R.id.comment_row_reply_button);
convertView.setTag(holder);
}
else
{
holder = (ViewHolder)convertView.getTag();
}
if (movies != null)
{
if (((movies.getParent_comment_id()).toString().equals("null")) && session.isLoggedIn()==true) {
holder.reply_button.setVisibility(View.VISIBLE);
}else{
holder.reply_button.setVisibility(View.INVISIBLE);
}
`if (!((movies.getParent_comment_id()).toString().equals("null")))
{
LayoutParams params = new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.WRAP_CONTENT);
params.setMargins(20, 0, 0, 0);
holder.comments_linearLayout.setLayoutParams(params);
}`
holder.commenter_textView.setText(movies.getUsername_commentor());
holder.commenter_textView.setTag(movies.getUser_id_commentor());
return convertView;
}
because you are setting margins (the brown font) in 'if' statement:
if (movies != null)
just take it out of this if block (for example put it just before the return point)
Right now this code is probably not executed at the first view load, since the movie is null. When the getView is called second time, the movie is not null, and the marigin is set according to your 'brown' code.
if this is not the solution - maybe the inside if statement condition is not true (the one that is in first 'brown' row). so.. your own logic prevents the marigins to be set as you want :)
Please let me know if it helps.
One way you could go about solving this problem is instead of using LayoutParams.setMargins(20, 0, 0, 0), you could create an empty TextView whose width is 20 dp by default and whose position will be to the left of your rows contents. It will be View.GONE by default, but when if (!((movies.getParent_comment_id()).toString().equals("null"))) happens, you can set that to View.VISIBLE
While scrolling the gallery last item is scrolled and stops at left margin. I want to stop the last item at right margin of the screen. i am showing 3 items at a time on screen thanks for any suggestions.
public View getView(int position, View convertView, ViewGroup parent) {
Gallery newArticleRow;
LinearLayout layout = (LinearLayout) convertView;
if (layout == null) {
Log.d("in home", "HomeActivityListViewAdapter--- new getView:" + position);
// Inflate the news article row
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.news_articles_row, null);
newArticleRow = (Gallery) convertView
.findViewById(R.id.news_articles_gallery);
DisplayMetrics metrics = new DisplayMetrics();
FishwrapHomeActivity.this.getWindowManager().getDefaultDisplay()
.getMetrics(metrics);
MarginLayoutParams mlp = (MarginLayoutParams) newArticleRow
.getLayoutParams();
mlp.setMargins(-(metrics.widthPixels - (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, 90, FishwrapHomeActivity.this
.getResources().getDisplayMetrics())), mlp.topMargin,
mlp.rightMargin, mlp.bottomMargin);
newArticleRow.setId(position);
newArticleRow.setLayoutParams(mlp);
convertView.setTag(newArticleRow);
convertView.setBackgroundColor(Color.WHITE);
convertView.setFocusableInTouchMode(false);
} else {
Log.d("in home", "HomeActivityListViewAdapter--- old getView:" + position);
// Get the newArticleRow HorizontialListView
newArticleRow = (Gallery) convertView.getTag();
}
// Set the adapter only if the ArticleRow
if (newArticleRow.getAdapter() == null || newArticleRow.getAdapter() != rowAdapters.get(position)) {
newArticleRow.setAdapter(rowAdapters.get(position));
newArticleRow.setOnItemClickListener(itemListener);
}
// Debug.stopMethodTracing();
return convertView;
}
#Rekha i think you should stop further scrolling functionality in that direction when position = lastitem - 1 element. You might want to do that through your Gallery instance ( gallery.getSelectedItemPosition() ) and the onscrollistener.
by the way, does this solve your previous "position restarts gallery in listview" issue? i have a similar issue that repeats my gallerys within my list when using a gallery holder.
HI all,
I have this "search results" ListView.
The search results can be of different "kinds" (different sections, call it).
To separate the "kinds" I add a row with a title. (I know about the expandable list, but can't use it for other reasons).
In my getView(), I check for a property, and if it's set, I change the background color of the row.
The problem: when I run a query that returns just a few rows (say 15), everything is fine. But when I run another that returns, say 600 rows, something goes wacko and it changes the background randomly, at a somewhat regular interval. Same thing happens when I'm running in debug mode and stop things in the middle.
So, it's definitely a timing issue.
I'm thinking this might be due to having to re-render the big list as the on-screen keyboard closes.
So, is the Adapter to blame? Is there any solution for this?
If the keyboard is the problem, is there a mechanism to tell the list "wait until the thing closes" before start rendering? (Not sure I like that, but it's better than getting a cute little rainbow...)
Thanks!
Llappall
--
Here's the adapter and the element layout (below):
private class ElementAdapter extends ArrayAdapter<Element> {
private ArrayList<Element> rows;
private Element.typeEnum type;
public ElementAdapter(Context context, int textViewResourceId, ArrayList<Element> rows) {
super(context, textViewResourceId, rows);
this.rows = rows;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.element, null);
}
Element row = rows.get(position);
if (row == null) {
return v;
}
v.setTag(row);
type = row.getType();
boolean isSectionType = type == Element.typeEnum.DIV118SECTION || type == Element.typeEnum.APPASECT ||
type == Element.typeEnum.APPBSECT || type == Element.typeEnum.AZSECT;
TextView title = (TextView) v.findViewById(R.id.title);
TextView body = (TextView) v.findViewById(R.id.body);
if (isSectionType) {
body.setMaxLines(5000);
}
title.setText(row.getTitle());
if (row.getBody() != null) {
body.setText(row.getBody());
}
if (type == Element.typeEnum.SEARCHLISTHEADER) {
v.setBackgroundColor(Color.rgb(230, 230, 250));
title.setBackgroundColor(Color.rgb(230, 230, 250));
body.setBackgroundColor(Color.rgb(230, 230, 250));
star.setBackgroundColor(Color.rgb(230, 230, 250));
}
return v;
}
}
==ELEMENT LAYOUT==
<TextView
android:id="#+id/body"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="1"
style="#style/ListItemSubTitle" />
</LinearLayout>
It would be much easier if you would post a getView() method here.
From what I can tell, you might be using recycled views wrong.
Check if background is changed to something if property is not set.
For example:
if (peoperty.isSet()) {
changeBackGround();
}
Just by itself will be wrong if you are reusing convertView, since the background will stay the same color how it was, when this view was used for a different row.
must be something like:
if (peoperty.isSet()) {
changeBackGround();
} else {
changeBackgroundToSomethingNeutral()
}
I took a liberty to rewrite that code for you, since you make too much weird stuff. Here's what I think is a optimized working code for your situation (didn't test any of it, but should work):
private class ElementAdapter extends ArrayAdapter<Element> {
public ElementAdapter(Context context, int textViewResourceId, ArrayList<Element> rows) {
super(context, textViewResourceId, rows);
this.rows = rows;
}
private final ArrayList<Element> rows;
#Override
public View getView(final int position, View convertView, final ViewGroup parent) {
ViewsHolder holder = null;
if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.element, parent, false);
holder = new ViewsHolder();
holder.title = (TextView) v.findViewById(R.id.title);
holder.body = (TextView) v.findViewById(R.id.body);
convertView.setTag(holder);
} else {
holder = (ViewsHolder) convertView.getTag();
}
final Element row = rows.get(position);
final Element.typeEnum type = row.getType();
if (type.equals(Element.typeEnum.DIV118SECTION) || type.equals(Element.typeEnum.APPASECT) ||
type.equals(Element.typeEnum.APPBSECT) || type.equals(Element.typeEnum.AZSECT)) {
body.setMaxLines(5000);
}
holder.title.setText(row.getTitle());
if (row.getBody() != null) {
holder.body.setText(row.getBody());
} else {
holder.body.setText("");
}
if (type == Element.typeEnum.SEARCHLISTHEADER) {
convertView.setBackgroundColor(Color.rgb(230, 230, 250));
holder.title.setBackgroundColor(Color.rgb(230, 230, 250));
holder.body.setBackgroundColor(Color.rgb(230, 230, 250));
//star.setBackgroundColor(Color.rgb(230, 230, 250)); // Where did that come from?
}
return convertView;
}
private final class ViewsHolder {
public TextView title;
public TextView body;
}
}
Couple of notes on the original code:
if (row == null) {
return v;
}
is wrong. You shouldn't have any null elements in your list for any position in the list. Even if you have, you shouldn't just throw some random view for the row. What you are doing here, is returning "v", that can very well be (and probably will be) some recycled old row, that still displays old data, and that's going to confuse the user. I made an assumption that you won't have any empty elements when wrote the code.
if (row.getBody() != null) {
body.setText(row.getBody());
}
Is almost ok, but again, if you are reusing convertView (which is some random previous row that isn't displayed anymore), then if body is actually null you will just be displaying the old data, which again will confuse the user. If body is null, just set the string empty.
P.S.
I recommend you to watch this for tips and tricks about how to work with ListView: The world of ListView
I'm working on an Android app that utilizes a ListView, in which each row is comprised of a text view and a progress bar. Things work smoothly unless the user has to scroll through a long list.
ProgressBars start taking on the progress of other ProgressBars not currently visible on the screen.
I understand that this is a common issue that stems from the implementation of GetView, but I'm wondering what the best course of action is to take with ProgressBars.
GetView:
public View getView(int position, View convertView, ViewGroup parent){
View row = convertView;
ViewWrapper wrapper;
ProgressBar myProgressBar;
int initProgress = myData.get(position).getProgress();
if (row == null){
LayoutInflater inflater = context.getLayoutInflater();
row = inflater.inflate(R.layout.row, null);
wrapper = new ViewWrapper(row);
row.setTag(wrapper);
}
else{
wrapper = (ViewWrapper)row.getTag();
}
RowModel model = getModel(position);
wrapper.getPid().setText(model.toString());
myProgressBar = wrapper.getProgressBar();
myProgressBar.setProgress(initProgress);
myProgressBar.setMax(100);
myProgressBar.setTag(new Integer(position));
return row;
}
ViewWrapper:
public class ViewWrapper {
View base;
TextView pid = null;
ProgressBar pb= null;
ViewWrapper(View base){
this.base = base;
}
TextView getPid(){
if(pid == null){
pid = (TextView)base.findViewById(R.id.pid);
}
return(pid);
}
ProgressBar getProgressBar(){
if(pb== null){
pb= (ProgressBar)base.findViewById(R.id.progressbar);
}
return(pb);
}
}
It seems that the issue is related to:
myProgressBar = wrapper.getProgressBar();
because that ProgressBar starts getting the behavior of a recycled ProgressBar. However, I want it to have its own behavior.
What's the best way to alleviate this? Thanks.
You may need to inflate the layout each time and not re-use the convertView that's passed in. This shouldn't be a problem unless you have A LOT of rows.
I had to implement a similar feature , here is what I did . I implemented the following outside getview
OnTouchListener - to listen to seekbar touch events
OnKeyListener - to listen to dpad and trakball event for the seekbar
I set these listeners for the seekbars from getView
Whenever the listeners were called , I would find the seekbars parent , then do the findviewbyid from the parent to the textview.
So now I have the textview which I have to update, and the seekbar. All I need to do was set the text from the array.
here is some code to help you.
private OnTouchListener touchListener = new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
View parent = (View) v.getParent();
TextView textView = (TextView) parent
.findViewById(R.id.id_grade_tooltip);
if (textView == null) {
} else {
SeekBar seekBar = (SeekBar) v;
textView.setText(String.valueOf(seekBar.getProgress())
+ "%");
}
return false;
}
};