How to get the index of an item at a specific offset from the top in Android ListView - android-widget

Is there a simple way for getting the index of a list item which is in a specific offset from the top?
For example, get the index of an item which appears 150 pixels from the top.

Since your goal is to find which list item is in the center of the screen, you could try something like the following:
(Make a custom class that extends ListView, such as MyListView.java)
public class MyListView extends ListView implements OnScrollListener {
public MyListView(Context context, AttributeSet attrs) {
super(context, attrs);
setOnScrollListener(this);
}
#Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
// Center the child currently closest to the center of the ListView when
// the ListView stops scrolling.
if (scrollState == OnScrollListener.SCROLL_STATE_IDLE) {
int listViewCenterX = getWidth() / 2;
int listViewCenterY = getHeight() / 2;
Rect rect = new Rect();
// Iterate the children and find which one is currently the most
// centered.
for (int i = 0; i < getChildCount(); ++i) {
View child = getChildAt(i);
child.getHitRect(rect);
if (rect.contains(listViewCenterX, listViewCenterY)) {
// this listitem is in the "center" of the listview
// do what you want with it.
final int position = getPositionForView(child);
final int offset = listViewCenterY - (child.getHeight() / 2);
break;
}
}
}
}
#Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
}
}

You can iterate through children and check each ones hit rectangle against the point you have.

Related

MonoGame - WinForm for homescreen?

I'm starting a project with monogame. I've made games with MonoGame before, but I felt the switching between multiple forms and monogame was clunky. For example I had a homescreen with buttons to Play, Hiscores & Quit. So I had forms for the homescreen and the hiscores. And then when you clicked Play the actualy MonoGame game would open.
Am I supposed to create everything in MonoGame? Or do I use panels in a single Form?
What I did to make it easier for myself is to make a class called "Screen", and just make a List<Screen> that holds all the different screens, so now, all I have to do to switch screen is set "Visible" to false or true on the screens I want to show or hide.
Here is part of how that class looks
public class Screen
{
public int ID;
public string Name;
public List<Form> Forms = new List<Form>();
public List<Label> Labels = new List<Label>();
public List<Button> Buttons = new List<Button>();
public List<Textbox> Textboxes = new List<Textbox>();
public List<EViewport> Viewports = new List<EViewport>();
public bool Visible;
// and a bunch of functions to add forms, buttons, do events, etc
// when adding a control, it's important that it is set to the right viewport
public Button AddButton(int _ID, string _Name, Texture2D _Sprite, int _Width, int _Height, Vector2 _Position, EViewport _Viewport, string _Text = "", bool _Visible = false)
{
Buttons.Add(new Button(_ID, _Name, _Sprite, _Width, _Height, new Vector2(_Position.X, _Position.Y), _Text, _Visible));
Button getButton = Buttons[Buttons.Count - 1];
getButton.ParentScreen = this;
getButton.ParentViewport = _Viewport;
return getButton;
}
public void Draw(SpriteBatch _spriteBatch, SpriteFont font, GameTime gameTime, Textbox focusedTextbox)
{
if (Visible)
{
// Draw only if screen is visible (this is not the full Draw function btw)
for(int j = 0; j < Viewports.Count; j++)
{
for(int i = 0; i < Buttons.Count; i++)
{
if(Buttons[i].ParentViewport.ID == Viewports[j].ID) // then draw
}
}
}
}
}
So basically all I do is add buttons, forms and viewports (because on my main menu I only need one viewport, but in-game I need 3 different viewports (one for game screen, one for UI and one for the chat) and then change their visibility like this:
storage.GetScreenByName("GameScreen").Visible = true;
(storage is just a singleton class that holds the sprite objects and screens in my game)
Oh, by the way, here's my EViewport class:
public class EViewport
{
/* Extended Viewport */
public Viewport _Viewport;
public Screen ParentScreen = new Screen();
public int ID;
public string Name;
public bool AllowResize;
public int MaxWidth;
public int MaxHeight;
public int MinHeight;
public float AspectRatio { get { return (float)MaxWidth / (float)MaxHeight; } }
public EViewport()
{
ID = -1;
}
public EViewport(int _ID, string _Name, int x, int y, int width, int height, bool _AllowResize = false, int _MinHeight = 0)
{
ID = _ID;
Name = _Name;
_Viewport = new Viewport(x, y, width, height);
AllowResize = _AllowResize;
MinHeight = _MinHeight;
MaxWidth = width;
MaxHeight = height;
}
public bool HasParentScreen()
{
return (ParentScreen.ID != -1);
}
}
I hope this helps, feel free to ask questions regarding how to implement such a system.

Foreach loop not working in android for custom object

I am trying to store the count of number of times an item from a list view is clicked in a custom array list but in my code the quantity of only the first clicked item is increasing and if i click on any other item then it gets added to the list view instead of increasing the quantity. Please tell me if you know any other method to get the count. Thanks
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Flowers item = (Flowers) parent.getAdapter().getItem(position);
if(item == null)
{
Toast.makeText(getBaseContext(),"item is null",Toast.LENGTH_LONG).show();
}else {
selectedItems items = new selectedItems();
items.setName(item.getName());
items.setCategory(item.getCategory());
Counter counter = new Counter();
if(selectedItemsArrayList.isEmpty())
{
counter.CartItemPosition = 0;
counter.MenuItemPosition = position;
counter.quantity = 1;
items.setQuantity(counter.quantity);
count.add(counter);
selectedItemsArrayList.add(items);
}
else
{
for(Counter c : count)
{
if(c.MenuItemPosition == position)
{
c.quantity = c.quantity + 1;
int i = c.CartItemPosition;
selectedItemsArrayList.get(i).setQuantity(c.quantity);
break;
}
else
{
Counter obj = new Counter();
obj.MenuItemPosition = position;
obj.CartItemPosition++;
obj.quantity=1;
count.add(obj);
items.setQuantity(obj.quantity);
selectedItemsArrayList.add(items);
return;
}
}
}
}
}
});
and my Counter class is
public class Counter {
public int CartItemPosition;
public int MenuItemPosition;
public int quantity;}

Is there any way to find a string's position and click on it using robotium?

I have the following list appearing on UI of an android application which tells about the date and the temperature on that date.
temp degree
11/01 --.-- c
11/02 21.7 c
11/03 22.5 c
Here I want to find the position of string "--.--" and then click on it, so that I can update the list. Is there any way to find the position of string? I know that solo.searchText() will tell whether the string is present or not, but what about the position?
// i think it will help you
listview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, final View view,
int position, long id) {
// TODO Auto-generated method stub
if(yourliststring.trim().equals("--.--"))
{
//your condition
}
else
{
//your condition
}
}
});
I got a simple way to find and click on the string
if(solo.searchText("--.--")){
solo.clickLongOnText("--.--");
}
All I need is to click on the string "--.--".
I'm not sure what position you need, however if you need position on screen you can simple do:
TextView textView = solo.getText("--.--"); // or solo.getText(Pattern.quote("--.--")); if needed
int[] xy = new int[2];
textView.getLocationOnScreen(xy);
final int viewWidth = textView.getWidth();
final int viewHeight = textView.getHeight();
final float x = xy[0] + (viewWidth / 2.0f);
final float y = xy[1] + (viewHeight / 2.0f);
this way you have central point of view (x, y).
If you need position of text in list, you can do:
private int getPosition(ListView listView, String text) {
for (int i = 0; i < listView.getAdapter().getCount(); i++) {
Object o = listView.getAdapter.getItemAtPosition(i);
if (o instanceof TextView) {
if (((TextView)o).getText().toString().equals(text)) {
return i;
}
}
}
return -1; // not found
}
you can call it for instance this way (set proper parameters):
int position = getPosition((ListView) solo.getView(ListView.class, 0), "--.--");
Everything written without testing and even compiling, however main idea should be fine.

Android ListView - scrolls back to top on update

I have a listview that gets additional views added on request, that's maintained by a BaseAdapter. How can I maintain scroll position after the update?
I know this has been asked a few times, but each time, the same solution has been put forward, which I have tried, which is to call adapter.notifyDataSetChanged(); after updating the ArrayList that contains the list contents.
How can I ensure that scroll position is maintained?
Implement an OnScrollListener in your activity class and then use the following code:
int currentFirstVisibleItem, currentVisibleItemCount, currentTotalItemCount;
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
this.currentFirstVisibleItem = firstVisibleItem;
this.currentVisibleItemCount = visibleItemCount;
this.currentTotalItemCount = totalItemCount;
}
public void onScrollStateChanged(AbsListView view, int scrollState) {
this.currentScrollState = scrollState;
this.isScrollCompleted();
}
private void isScrollCompleted() {
if (currentFirstVisibleItem + currentVisibleItemCount >= currentTotalItemCount) {
if (this.currentVisibleItemCount > 0
&& this.currentScrollState == SCROLL_STATE_IDLE) {
//Do your work
}
}
}
If you are using AsyncTask for updating your data, then you can include the following in your PostExecute() in order to maintain the Scroll position:
list.setAdapter(adapter);
list.setSelectionFromTop(currentFirstVisibleItem, 0);
I hope this helps.
The approach I take is to call ListView.setSelection(position) to scroll to the desired position after the update.
Depending on where you're calling it from, you might need to call requestFocusFromTouch before calling setSelection in order to ensure the item gets positioned appropriately.
This code will help you out....
// get position of listview
int index = listView.getFirstVisiblePosition();
View v = listView.getChildAt(0);
int top = (v == null) ? 0 : v.getTop();
// notify dataset changed or re-assign adapter here
//re-assign the position of listview after setting the adapter again
listView.setSelectionFromTop(index, top);
Cheers :)
You can try this:
//Get the top position from the first visible element
int fVisible = list.getFirstVisiblePosition();
View vFirst = list.getChildAt(0);
int pos = 0;
if (vFirst != null) pos = vFirst.getTop();
//Restore the position
list.setSelectionFromTop(fVisible, pos);
You can do as below. If you want to load more data with scroll to bottom it will have some change.
int currentFirstVisibleItem, currentScrollState;
int countChange = 0;
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
Log.d("Scroll", "Scrolling");
this.currentFirstVisibleItem = firstVisibleItem;
countChange = 0;//during touching you can decide not to refresh by scroll
}
public void onScrollStateChanged(AbsListView view, int scrollState) {
Log.d("Scroll", "Changed");
this.currentScrollState = scrollState;
if (scrollState == SCROLL_STATE_TOUCH_SCROLL) {
countChange = 0;
}
if (++countChange > 1) {
//scroll to top and release touch change=2. Simple scroll and release touch change=1
this.isScrollCompleted();
countChange = 0;
}
}
private void isScrollCompleted() {
Log.d("Load", "Reload");
if (currentFirstVisibleItem == 0) {
//Your loading go here
}
}

Custom ProgressBar widget

I am trying to do something similar to this but in Android.
In Android I can extend the ProgressBar but I am doubting of how to add the TextViews on top. In iphone it was easy because I can use absolute positions, but not here.
Any ideas?
EDIT:
I decided to use SeekBar instead of ProgressBar to add the thumb drawable. I commented below. Some points to notice:
I am using hardcoded values, actually three but it can be more or less.
When the thumb is moved it moves to 50 but it should move to the different options.
I am using pixels instead of dpi. I should fix that.
I need to solve the lack of animation when the thumb moves.
My progress so far:
public class SliderFrameLayout extends FrameLayout implements OnSeekBarChangeListener {
private SeekBar mSlider;
private Context mContext;
private int mSize = 3;
private TextView[] mTextViews;
private String[] mTexts = {"Nafta", "Gas", "Gasoil"};
public SliderFrameLayout(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
setWillNotDraw(false);
mTextViews = new TextView[mSize];
addSlider();
addTextViews();
}
private void addTextViews() {
for ( int i=0 ; i < mSize ; i++ ) {
TextView tv;
tv = new TextView(mContext);
tv.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT));
tv.setText(mTexts[i]);
mTextViews[i] = tv;
addView(tv);
}
}
private void addSlider() {
FrameLayout fl = new FrameLayout(mContext, null);
LayoutParams params = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
fl.setLayoutParams(params);
fl.setPadding(30, 30, 30, 0);
mSlider = new SeekBar(mContext, null);
LayoutParams lp = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
//lp.setMargins(30, 30, 30, 0);
//mSlider.setPadding(30, 30, 30, 0);
mSlider.setLayoutParams(lp);
//mSlider.setMax(mSize-1);
mSlider.setThumbOffset(30);
//mSlider.setProgressDrawable(mContext.getResources().getDrawable(R.drawable.slider_track));
//mSlider.setThumb(mContext.getResources().getDrawable(R.drawable.slider_thumb));
mSlider.setOnSeekBarChangeListener(this);
//addView(mSlider);
fl.addView(mSlider);
addView(fl);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Rect rectf = new Rect();
mSlider.getLocalVisibleRect(rectf);
Log.d("WIDTH :",String.valueOf(rectf.width()));
Log.d("HEIGHT :",String.valueOf(rectf.height()));
Log.d("left :",String.valueOf(rectf.left));
Log.d("right :",String.valueOf(rectf.right));
Log.d("top :",String.valueOf(rectf.top));
Log.d("bottom :",String.valueOf(rectf.bottom));
int sliderWidth = mSlider.getWidth();
int padding = sliderWidth / (mSize-1);
for ( int i=0 ; i < mSize ; i++ ) {
TextView tv = mTextViews[i];
tv.setPadding(i* padding, 0, 0, 0);
}
}
#Override
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
// TODO Auto-generated method stub
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
// TODO Auto-generated method stub
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
Log.d("SEEK", "value: " + seekBar.getProgress());
seekBar.setProgress(50);
}
}
You're already overriding onDraw, why not just draw the text strings yourself? Rather than go through the overhead of adding TextViews and messing with the padding, just use canvas.drawText to physically draw the text strings in the right place.
You can specify the style and color of the text using a Paint object:
Paint textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
textPaint.setColor(r.getColor(R.color.text_color));
textPaint.setFakeBoldText(true);
textPaint.setSubpixelText(true);
textPaint.setTextAlign(Align.LEFT);
And get the exact positioning by using the measureText method on that Paint object to find what width a particular string would be when drawn on a canvas:
textWidth = (int)textPaint.measureText(mTexts[i]);
Then you can iterate over your array of text strings and draw each string in the right place.
#Override
protected void onDraw(Canvas canvas) {
int myWidth = getMeasuredWidth()-LEFT_PADDING-RIGHT_PADDING;
int separation = myWidth / (mSize-1);
for (int i = 0; i++; i < mSize) {
int textWidth = (int)textPaint.measureText(mTexts[i]);
canvas.drawText(mTexts[i],
LEFT_PADDING+(i*separation)-(int)(textWidth/2),
TOP_PADDING,
textPaint);
}
}
You'll probably want to do the measurements in onMeasure instead of onDraw, and you should probably only measure the width of each string when you change the text or the paint, but I've put it all in one place to (hopefully) make it easier to follow.
Just a try. You could put your custom progressBar inside a FrameLayout then, inside this layout, you have to add three TextViews with fill_parent as width.
Then you can align the three texts in this way: left, center and right. Your texts shouldn't overwrite and you can adjust a little their position using margins.
You can use this... not exact what you looking for... but really easy to set up and customize...
You can set the TextViews to have:
android:layout_width="0dp"
android:layout_weight="1"
This will let the android framework take care of the placing of the TextViews and save you from manually calculating the padding of each one.