GridView, Get Item's parent View - android

I'm trying to send clicks to my child elements in GridView with a single touch event. So far, I can retrieve the data of the child element, but cannot perform a click on it.
Let me explain a bit more on the layout of things...
GridView - Touch Event Handler here...
LinearLayout - onClick listeners here...
TextView - Just some text...
An adapter fills GridView with LinearLayout's who have onClick events defined. These layouts contain TextViews where TextView.setText("Some data from my dataset")
I have an onTouch listener which is currently listening to touch events on the GridView, and is successfully finding the data of TextView depending on the position of the finger.
How do I get the TextView's parent view, and call performClick at the user's finger position?
This is the current click handler, containing what I've got so far...
Assume GridView & Adapter are initialised properly...
#Override
public boolean onTouch(View v, MotionEvent event) {
int action = MotionEventCompat.getActionMasked(event);
switch(action)
{
case (MotionEvent.ACTION_DOWN) :
case (MotionEvent.ACTION_MOVE) :
int position = GridView.pointToPosition((int)event.getX(),(int)event.getY());
if (position != -1)
{
// I have looked at the other .get methods, and doing GridView.getXYZ (Where XYZ could be any method) and couldn't get anywhere...
String item = Adapter.getItem(position);
Log.d("TouchEvent","Action was DOWN/MOVE on " + item);
return true;
}
case (MotionEvent.ACTION_UP) :
Log.d("TouchEvent","Action was UP");
return true;
case (MotionEvent.ACTION_CANCEL) :
Log.d("TouchEvent","Action was CANCEL");
return true;
case (MotionEvent.ACTION_OUTSIDE) :
Log.d("TouchEvent","Movement occurred outside bounds " +
"of current screen element");
return true;
default :
return true;
}
}
});
Thanks!
Also thought to mention, this GridView is contained within a fragment. I doubt it would change the world, but might affect the solutions you guys have.

Aaahh.. Something we need to try,
Implement method like,
private View getViewByPosition(GridView gridView, int position) {
int firstPosition = gridView.getFirstVisiblePosition();
int lastPosition = gridView.getLastVisiblePosition();
if ((position < firstPosition) || (position > lastPosition))
return null;
return gridView.getChildAt(position - firstPosition);
}
Now, call this method,
if (position != -1)
{
// I have looked at the other .get methods, and doing GridView.getXYZ (Where XYZ could be any method) and couldn't get anywhere...
GridView gridView = (GridView) v;
View touchedView = getViewByPosition(gridView, position);
String item = Adapter.getItem(position);
Log.d("TouchEvent","Action was DOWN/MOVE on " + item);
return true;
}

Try this
gridview.setOnItemClickListener(new OnItemClickListener() { public void onItemClick(AdapterView parent, View v,
int position, long id)
{ // Send intent to SingleViewActivity Intent i = new Intent(getApplicationContext(), SingleViewActivity.class); // Pass image index
i.putExtra("id", position);
startActivity(i);
}
});
After this create SingleViewActivity.java class
public class SingleViewActivity extends Activity { #Override
public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.single_view);
// Get intent data Intent i = getIntent();
// Selected image id
int position = i.getExtras().getInt("id"); ImageAdapter imageAdapter = new ImageAdapter(this);
ImageView imageView = (ImageView) findViewById(R.id.SingleView); imageView.setImageResource(imageAdapter.mThumbIds[position]); }
}

Related

After i update background color of selected item in listview, if i scroll background changes to random item and it selects multiple items too, why?

My code :
ArrayList<Integer> selectedItemIds = new ArrayList<>();
boolean isItemSelected = false;
main_listview.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
#Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
Object object = parent.getItemAtPosition(position);
if(object instanceof Listview_Item_Details)
{
TextView itemName = (TextView) view.findViewById(R.id.listview_itemName);
TextView itemDetails = (TextView) findViewById(R.id.listview_itemDetails);
if(!selectedItemIds.isEmpty())
{
for(int i = 0; i < selectedItemIds.size();i++)
{
if(selectedItemIds.get(i) == position)
{
isItemSelected = true;
if(selectedItemIds.size() == 1)
{
selectedItemIds.clear();
}
else
{
selectedItemIds.remove(i);
}
}
}
if(isItemSelected)
{
view.findViewById(R.id.custom_listview_item).setBackgroundResource(R.drawable.listview_item_background);
itemName.setTextColor(getResources().getColor(R.color.colorBlack));
itemDetails.setTextColor(getResources().getColor(R.color.colorGray_Dark));
isItemSelected = false;
}
else
{
selectedItemIds.add(position);
view.findViewById(R.id.custom_listview_item).setBackgroundResource(R.drawable.listview_selected_item_background);
itemName.setTextColor(getResources().getColor(R.color.colorWhite));
itemDetails.setTextColor(getResources().getColor(R.color.colorPrimaryDark));
}
}
else
{
selectedItemIds.add(position);
view.findViewById(R.id.custom_listview_item).setBackgroundResource(R.drawable.listview_selected_item_background);
itemName.setTextColor(getResources().getColor(R.color.colorWhite));
itemDetails.setTextColor(getResources().getColor(R.color.colorPrimaryDark));
}
}
return true;
}
});
NOTE : "custom_listview_item" is RelativeLayout of custom layout for item, in which both textviews are.
Now everythings works but like i said in question, if i DONT scroll the listview and selected/unselect multiple items, it works but i scroll it randomly changes background of multiple items and even changes background of selected items too.
What is the problem here?
Use Recyclerview instead of Listview to handle this kind of situations and customizing the view items.

onClickListener in getView() method messes up MultiChoiceModeListener()

So I have a GridView that implements the multiple choice mode listener , and every time the user taps the item it should change it's background image ; and when he/she long taps , the multi choice toolbar should appear.
However since I have on click listener in getView() it somehow blocks the other one.
(if I remove the listener from getView() , the other one works just fine)
Any advices ?
Here's my code:
MultiChoiceListener:
gView.setChoiceMode(GridView.CHOICE_MODE_MULTIPLE_MODAL);
checkedPos = new SparseBooleanArray();
gView.setMultiChoiceModeListener(new GridView.MultiChoiceModeListener() {
#Override
public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) {
currentArray = gView.getCheckedItemPositions();
int itemCount = gView.getCheckedItemCount();
switch (itemCount){
case 1:
mode.setSubtitle("One item selected.");
break;
default:
mode.setSubtitle(itemCount + " items selected.");
break;
}
...
getView():
convertView.setLongClickable(true);
final Holder finalHolder = holder;
convertView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(!pressed) {
finalHolder.img.setBackground(ContextCompat.getDrawable(context, R.drawable.ic_pause_bg));
pressed = true;
}
else{
finalHolder.img.setBackground(ContextCompat.getDrawable(context, R.drawable.ic_noise_bg));
pressed = false;
}
}
});
Thank you for your time!
Nevermind, I worked it out. I'm going to leave my answer if someone needs a solution for the same problem.
First of all forget about the listener in the getView() method , instead go where you have the code for your MultiChoiseModeListener and call setOnItemClickListener() for your gridView -> using the id of the image you want to change constantly:
gView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
view.setSelected(true);
ImageView image = (ImageView) view.findViewById(R.id.noise_image); //use the id given in your layout
if(!itemPressed.get(position)) {
image.setBackground(ContextCompat
.getDrawable(mContext, R.drawable.ic_running));
itemPressed.put(position,true);
}
else{
itemPressed.put(position,false);
image.setBackground(ContextCompat.getDrawable(mContext,R.drawable.ic_normal));
}
Doing so, both listeners will work.
Notice that itemPressed is a Map in order to memorize
which item was clicked so when changing background images , there is
no confusion.

Fetching the view at a position of a GridView gives NullPointerException

I have an activity which is populated by a GridView containing a 3x3 matrix
of LinearLayouts (which in turn have ImageViews). When I try to get a position
of view after some the GridView is completely loaded, I get proper results.
However, when I try to fetch the view at a given position from onResume(),
it gives a NullPointerException. Why does this happen? Isn't the GridView
initialized by the time onResume() is called?
Are there any workaround for this?
The part where I am trying to fetch the view of a given position -
private void systemsMove(String userBlock) {
int position, row, column;
String systemsBlock = (userBlock.equalsIgnoreCase("Zero") ? "One" : "Zero");
for (position = 0, row = 0, column = 0;
(mModel.array[row][column] == 0
|| mModel.array[row][column] == 1) && position < 9;
position++) {
row = position / MAX_COLUMN;
column = position % MAX_COLUMN;
}
if (position == 9) finish();
mModel.changeBlock(systemsBlock, row, column);
View view = getViewByPosition(position);
if (view == null)
Log.i(TAG, "The view is NULL!!!");
ImageView imageView = (ImageView) view.findViewById(R.id.imageview);
if (systemsBlock.equalsIgnoreCase("Zero"))
imageView.setImageResource(R.drawable.one);
else if (systemsBlock.equalsIgnoreCase("One"))
imageView.setImageResource(R.drawable.zero);
}
Code that works from OnItemClickListener -
gridView.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
ImageView imageView = (ImageView) view.findViewById(R.id.imageview);
String systemBlock = "";
if (userBlock.equalsIgnoreCase("One")) {
imageView.setImageResource(R.drawable.one);
systemBlock = "Zero";
} else if (userBlock.equalsIgnoreCase("Zero")) {
imageView.setImageResource(R.drawable.zero);
systemBlock = "One";
}
int row = position / MAX_COLUMN;
int column = position % MAX_COLUMN;
mModel.changeBlock(userBlock, row, column);
if (mModel.checkForWin()) {
mModel.deInitialize();
finish();
}
systemsMove(systemBlock);
if (mModel.checkForWin()) {
mModel.deInitialize();
finish();
}
}
});
Method for getting View for a position in a GridView from this SO question -
public View getViewByPosition(int position) {
int firstPosition = gridView.getFirstVisiblePosition();
int lastPosition = gridView.getLastVisiblePosition();
if ((position < firstPosition) || (position > lastPosition))
return null;
return gridView.getChildAt(position - firstPosition);
}
And this is how I call it from onResume() -
protected void onResume() {
super.onResume();
String userBlock = getIntent().getStringExtra("BlockSelected");
if (userBlock.equalsIgnoreCase("Zero")) systemsMove(userBlock);
}
GridView will populate itself from the adapter during the first layout pass. This means it won't have children in onCreate(). The easiest way to wait for the first layout pass is to use a ViewTreeObserver (see View.getViewTreeObserver()) to register a global layout listener. The first time the listener is invoked, the grid should contain children.
Note that if you want to change the background of one of the children of a GridView you really should do it from the adapter. Since views are recycled the background may appear to "move" to another view later on

swap items in a Gridview trouble with the dropped position in Android

i have been trying to swap items in a Grid view, and this is where i got:
xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/parent_layout"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<GridView
android:id="#+id/grid_view"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:horizontalSpacing="10dip"
android:numColumns="4"
android:verticalSpacing="10dip" />
</RelativeLayout>
main activity class:
public class MainActivity extends Activity implements OnDragListener,
OnItemLongClickListener {
ArrayList drawables;
GridView gridView;
private BaseAdapter adapter;
private int draggedIndex = -1;
private int droppedIndex = -1;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
drawables = new ArrayList();
drawables.add(R.drawable.ic_launcher);
drawables.add(R.drawable.ic_launcher1);
drawables.add(R.drawable.ic_launcher2);
drawables.add(R.drawable.ic_launcher);
drawables.add(R.drawable.ic_launcher);
drawables.add(R.drawable.ic_launcher);
drawables.add(R.drawable.ic_launcher);
drawables.add(R.drawable.ic_launcher);
gridView = (GridView) findViewById(R.id.grid_view);
gridView.setOnItemLongClickListener(MainActivity.this);
gridView.setAdapter(adapter = new BaseAdapter() {
#Override
// Get a View that displays the data at the specified position in
// the data set.
public View getView(int position, View convertView,
ViewGroup gridView) {
// try to reuse the views.
ImageView view = (ImageView) convertView;
// if convert view is null then create a new instance else reuse
// it
if (view == null) {
view = new ImageView(MainActivity.this);
}
view.setImageResource((Integer) drawables.get(position));
view.setTag(String.valueOf(position));
return view;
}
#Override
// Get the row id associated with the specified position in the
// list.
public long getItemId(int position) {
return position;
}
#Override
// Get the data item associated with the specified position in the
// data set.
public Object getItem(int position) {
return drawables.get(position);
}
#Override
// How many items are in the data set represented by this Adapter.
public int getCount() {
return drawables.size();
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public boolean onDrag(View view, DragEvent dragEvent) {
switch (dragEvent.getAction()) {
case DragEvent.ACTION_DRAG_STARTED:
// Ignore this event
return true;
case DragEvent.ACTION_DRAG_ENTERED:
// Ignore this event
return true;
case DragEvent.ACTION_DRAG_EXITED:
// Ignore this event
return true;
case DragEvent.ACTION_DRAG_LOCATION:
// Ignore this event
return true;
case DragEvent.ACTION_DROP:
// Dropped inside a new view\
adapter.notifyDataSetChanged();
ImageView v2 = (ImageView)view.getParent();
final int position1 = gridView.getPositionForView(v2);
if (position1 >= 0)
{
final long droppedIndex = gridView.getAdapter().getItemId(position1);
}
Object item1 = gridView.getAdapter().getItem(draggedIndex);
Object item2 = gridView.getAdapter().getItem(droppedIndex);
drawables.remove(draggedIndex);
drawables.remove(droppedIndex);
drawables.add(droppedIndex,item1);
drawables.add(draggedIndex,item2);
draggedIndex = -1;
droppedIndex = -1;
adapter.notifyDataSetChanged();
case DragEvent.ACTION_DRAG_ENDED:
//
view.setOnDragListener(null);
return true;
}
return false;
}
#Override
public boolean onItemLongClick(AdapterView gridView, View view,
int position, long row) {
ClipData.Item item = new ClipData.Item((String) view.getTag());
ClipData clipData = new ClipData((CharSequence) view.getTag(),
new String[] { ClipDescription.MIMETYPE_TEXT_PLAIN }, item);
view.startDrag(clipData, new View.DragShadowBuilder(view), null, 0);
view.setVisibility(View.INVISIBLE);
draggedIndex = position;
return true;
}
}
my problem is in DragEvent.ACTION_DROP. I works like this:
I drag one item and, when drop it in another place, the item disappears. And that is all.
Supposedly, first retrieve both positions: the position of the item dragged (draggedIndex) and the position where the item is dropped (droppedIndex). After, i remove both items and add them to the array again in the opposite positions (the item dragged goes to droppedIndex and the other goes to the draggedIndex, so they are exchanged/swaped)
I wonder if it is a good way to do this, or if i made any mistakes trying to retrieve the dropped position (droppedIndex).
any ideas?
Before removing the item , just add the item into dropped position. Then remove the corresponding item by incrementing the dropped position by 1.
case DragEvent.ACTION_DROP:
....
drawables.add(droppedIndex,item1);
drawables.add(draggedIndex+1,item2);
drawables.remove(draggedIndex+2);
drawables.remove(droppedIndex+2);
....
hope this will help you.
I took a slightly different approach to get the dropped index. For an ACTION_DROP event, getX() and getY() return the X and Y position of the drag point at the moment of the drop, using the coordinate system of the View that received the drop (i.e. the gridview).
float dropX = event.getX();
float dropY = event.getY();
Once you have the x and y co-ordinates you can calculate the corresponding row and column in your grid view, and then use something like the following to get the index of the object in your data array (I have a 4 x 4 grid):
index = row * 4 + column;
Finally, I'm using an array list (targetDrawables) to hold the references to my gridview contents, so to reorder use:
targetDrawables.remove(draggedIndex);
targetDrawables.add(droppedIndex, draggedContents);
// Invalidate the view to force a redraw of the Grid View
imageAdapter.notifyDataSetChanged();
Your code is fine; just replace
Object item1 = gridView.getAdapter().getItem(draggedIndex);
Object item2 = gridView.getAdapter().getItem(droppedIndex);
drawables.remove(draggedIndex);
drawables.remove(droppedIndex);
drawables.add(droppedIndex,item1);
drawables.add(draggedIndex,item2);
with
Collections.swap(drawables, draggedIndex, droppedIndex);
It swaps position of list and now it works!

How to Call back data from child Activity and make the images in parent activity transparent

I have images in gridview. These images are shown in an activity. When one of the images is clicked, new activity is started with this image. In this activity, If user inputs correct answer, new activity is started that indicates the answer is correct. After user inputs correct answer, I want to set this image more transparent with a check mark in gridwiew.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_level1);
initComponent();
gva.setAdapter(new ImageAdaptera(getApplicationContext()));
gva.setOnItemClickListener(new OnItemClickListener()
{
public void onItemClick(AdapterView<?> parent, View v,
int position, long id) {
switch (position) {
case 0:
{
Intent intenta = new Intent (getBaseContext(), AA.class).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivityForResult(intenta,0);
}
break;
case 1:
{
Intent intentb = new Intent (getBaseContext(), AB.class).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivityForResult(intentb,0);
}
break;
case 2:
{
Intent intentc = new Intent (getBaseContext(), AC.class).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivityForResult(intentc,0);
}
break;
}}
}
My Image Adapter:
public View getView(int position, View convertView, ViewGroup parent) {
ImageView imageViewa;
if (convertView == null) { // if it's not recycled, initialize some attributes
imageViewa = new ImageView(mContext);
imageViewa.setLayoutParams(new GridView.LayoutParams(85, 85));
imageViewa.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageViewa.setPadding(8, 8, 8, 8);
} else {
imageViewa = (ImageView) convertView;
}
imageViewa.setImageResource(imagesa[position]);
return imageViewa;
}
Child Activity:
#Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if ((event.getAction() == KeyEvent.ACTION_DOWN) &&
(keyCode == KeyEvent.KEYCODE_ENTER)) {
String check = input.getText().toString().replace(" ","");
Editor editor = mGameSettings.edit();
editor.putString(GAME_PREFERENCES_answeraa, check);
editor.commit();
if(check.equalsIgnoreCase("petronet")){
display.setText("correct");
Toast.makeText(AA.this,"CORRECT",Toast.LENGTH_SHORT).show();
Intent data = new Intent();
// TODO Add extras or a data URI to this intent as appropriate.
setResult(RESULT_OK, data);
input.setEnabled(false);Guruapp.levela++;Guruapp.count++;
int hc2 = mGameSettings.getInt(GAME_PREFERENCES_hint, Guruapp.count);
Guruapp.count = hc2;
finish();
}
else{
display.setText("Wrong");
Toast.makeText(AA.this,"WRONG",Toast.LENGTH_SHORT).show();
return false;
}
Why don't you make:
a public static ArrayList imageResponded=new ArrayList(numberOfImages);
set the imageResponded arrayList elements to false
then when the user choose an image, you take that image's index to know what image to show in your next activity
when the user inputs the correct answer regarding of the image showed you
when you return in your grid view activity, in onResume when you recreate the grid view with images, before you place the image in a box you check first if on that index the imageResponded.get(index) return true, if it does you set the alpha of image on 75% and put a tick in lower right of the image

Categories

Resources