Prevent GridView reset scroll to top when element is tapped? - android

I have a GridView that is populated by all apps installed on the device. The user can select certain apps here. I want the selected apps to be opaque and non-selected to be partially transparent. I did this with the following:
public View getView(int position, View convertView, ViewGroup parent) {
LinearLayout linearLayout = new LinearLayout(mContext);
linearLayout.setOrientation(LinearLayout.VERTICAL);
linearLayout.setGravity(Gravity.CENTER_HORIZONTAL);
LinearLayout.LayoutParams layoutParamsText = new LinearLayout.LayoutParams(150, 90);
ImageView imageView = new ImageView(mContext);
TextView appLabel = new TextView(mContext);
final OurAppInfo info = (OurAppInfo) getItem(position);
if(!installedApplications.contains(info)){
AlphaAnimation alpha = new AlphaAnimation(0.4F, 0.4F);
alpha.setDuration(0);
alpha.setFillAfter(true);
linearLayout.startAnimation(alpha);
}
String appName = info.label;
if (appName.length() > 25) {
appName = appName.substring(0, 25);
appName = appName + "...";
}
appLabel.setText(appName);
appLabel.setTextColor(Color.BLACK);
appLabel.setGravity(Gravity.CENTER_HORIZONTAL);
appLabel.setTypeface(null, Typeface.BOLD);
imageView.setImageDrawable(info.drawableAppIcon);
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setLayoutParams(new GridView.LayoutParams(110, 110));
appLabel.setTextSize(15);
linearLayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (installedApplications.contains(info)){
installedApplications.remove(info);
receiveUpdate(installedApplications, false, false);
} else {
installedApplications.add(info);
Collections.sort(installedApplications);
receiveUpdate(installedApplications, false, false);
}
}
});
appLabel.setLayoutParams(layoutParamsText);
linearLayout.addView(imageView);
linearLayout.addView(appLabel);
return linearLayout;
}
This is part of the GridAdapter extends BaseAdapter. The code works as expected, when I tap on an app it is either removed from or added to the list and according to transparency is set. However, whenever I tap on an element in the GridView, the view is reset and I am brought to the top of the scrollable GridView. Obviously, this isn't a problem for a small number of apps, but if you're selecting apps near the XYZ letters, every time you select one you are brought back to ABC. How can I prevent this from happening?

It looks like you're refreshing the adapter whenever you make changes that makes the grid go back to initial position. You could try saving and restoring the position before making any changes to the adapter.
//Before refreshing the adapter you get both X and Y position
int xPos = grid.getScrollX();
int yPos = grid.getScrollY();
Then you update your adapter.
After the adapter is recreated you restore the grid position:
grid.scrollTo(xPos, yPos);
You could also use (everytime possible) the method notifyDataSetChanged() instead of creating a new adapter.
Hope it helps.

Check all child views for automatic height or width.
I guess gridview calculates size of this views whenever you change data.
This was solution in my case.
In my case changed this:
<ImageView
android:id="#+id/image"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
To this:
<ImageView
android:id="#+id/image"
android:layout_width="100dp"
android:layout_height="100dp" />

Related

".addView()" for simple views

As you can see in the image, I can select the view and 3 ImageViews get added using "_root.addView(dragIcon);".
My problem is that the view is a simple view and not a ViewGroup , which means that in this picture i had to add the 3 images to the RelativeView Background "root.addView(dragIcon);" Instead of to the Green rectangle view shown in the image.
I'm pretty sure i can't change the View to a ViewGroup becuase a lot of methods (ex. onTouch) require a "View". I've tried casting the View to a ViewGroup "((ViewGroup) view).addView(dragIcon);" but that did't work.
You can make multiple Views in the app and drag them around, so I need to make the 3 images children to the specific parent View.
Any suggestions are appreciated, thanks!
Here is the part of the code that's relevant to this question...
_root = (ViewGroup)findViewById(R.id.root); //This is the background
_view = new View(this); //This is the View (Green in the Image)
private void selectView(final View view) {
view.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(final View view, final MotionEvent event) {
view.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
ImageView dragIcon, sizeIconTop, sizeIconBottom;
if (view.getTag(R.string.viewSelected) != "1") {
view.setBackgroundColor(0xFF00AA00);
view.setTag(R.string.viewSelected, "1");
double Ypos = view.getTranslationY() - view.getHeight() / 2;
// Set draggable (6*3 grid on the right)
dragIcon = new ImageView(MainActivity.this);
dragIcon.setImageResource(R.drawable.drabicon);
RelativeLayout.LayoutParams imgParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
imgParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
imgParams.setMargins(0,0,30,0);
dragIcon.setLayoutParams(imgParams);
dragIcon.setTranslationY((float) Ypos + 70 + view.getHeight() / 2);
_root.addView(dragIcon); //Need to change from _root.addView to view.addView
// Set size top (White line at the top)
sizeIconTop = new ImageView(MainActivity.this);
sizeIconTop.setImageResource(R.drawable.resize);
RelativeLayout.LayoutParams stImgParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
stImgParams.setMargins(0,0,30,0);
stImgParams.addRule(RelativeLayout.CENTER_HORIZONTAL, RelativeLayout.TRUE);
sizeIconTop.setLayoutParams(stImgParams);
sizeIconTop.setTranslationY((float) Ypos + 99);
_root.addView(sizeIconTop); //Need to change from _root.addView to view.addView
// Set size bottom (White line at the bottom)
sizeIconBottom = new ImageView(MainActivity.this);
sizeIconBottom.setImageResource(R.drawable.resize);
RelativeLayout.LayoutParams sbImgParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
sbImgParams.setMargins(0,0,30,0);
sbImgParams.addRule(RelativeLayout.CENTER_HORIZONTAL, RelativeLayout.TRUE);
sizeIconBottom.setLayoutParams(sbImgParams);
sizeIconBottom.setTranslationY((float) Ypos + 93 + view.getHeight());
_root.addView(sizeIconBottom); //Need to change from _root.addView to view.addView
} else { //Ignore this part
//((ViewGroup) view).removeView(dragIcon);
//((ViewGroup) view).removeView(sizeIconTop);
//((ViewGroup) view).removeView(sizeIconBottom);
view.setBackgroundColor(0xFF00FF00);
view.setTag(R.string.viewSelected, "0");
}
}
});
Even though the question is a bit confusing, after analysing your code I figured out what you wanted to do.
Unfortunately, you have to choose whether to use a View (and not being able to attach the ImageViews) or using a ViewGroup (and handling the events yourself).
Since your View is a View, and your 3 ImageViews are also Views (means they are at the same level of usage), you can not add the last 3 to the first.
The rule is : You can add ViewGroups and Views to a ViewGroup, but you can not add Views or ViewGroups to a View. Views are supposed to be the elementary block of Android design.
void addView (View child)
Adds a child view. If no layout parameters
are already set on the child, the default parameters for this
ViewGroup are set on the child.
In my opinion, I would make View a ViewGroup and take care of the TouchEvents by myself.
Check this documentation/code regarding TouchEvents on ViewGroups
Let me know of your progress. Will be glad to help you.
Regards,

Get position of dynamic Image View

Outline
My application has a main Image View and below main view, it has dynamic horizontal imageview .
Code for dynamic image view
ImageView imageall = new ImageView(FullImage.this);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(175, 175);
params.setMargins(10, 0, 0, 0);
imageall.setLayoutParams(params);
imageall.setBackgroundResource(R.drawable.imageview_border);
Picasso.with(context_tab1).load("http://example.com//upload/image/" + stringList.get(in)).into(imageall);
// Adds the view to the layout
layout.addView(imageall);
imageall.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int position = (Integer) v.getTag();
image = "http://example.com/x/upload/image/" + stringList.get(position);
Picasso.with(context_tab1).load(image).into(fullimage);
}
});
}
I populate the dynamic imageview from array list. Everything works fine till this part.
Problem
Now, On Click of the dynmic imageview must get that image view position and change as the main imageview .
This is not working for me.
For better understanding please find the image attached.
Thanks.
No need of getting position of dynamic ImageView..
While creating the dynamic ImageView you can set Ids to them and also set the onClickListener on them. Override the Onclick method, check the Id with your Ids you gave to dynamic ImageView and replace the Main view's as per the ImageView clicked..
Happy coding.. :)

Setting LayoutParams via post method in List View adapter

I am trying to set a margin in a text view and padding in a linear layout in a list view adapter. Basically, if the text view has 2 or less lines of text I am creating a margin/padding for that list item.
Here is the code:
public class StockCountListAdapter extends ArrayAdapter<StockCountItem> {
private TextView txtProduct;
private LinearLayout llStockCountItem;
public StockCountListAdapter(Context context, int textViewResourceId, List<StockCountItem> objects) {
super(context, textViewResourceId, objects);
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View rowView = inflater.inflate(R.layout.stock_count_list_item, parent, false);
txtProduct = (TextView) rowView.findViewById(R.id.stock_count_item_product);
llStockCountItem = (LinearLayout) rowView.findViewById(R.id.ll_stock_count_item);
StockCountItem item = getItem(position);
txtProduct.setText(item.Product);
llStockCountItem.post(new Runnable() {
#Override
public void run() {
if (txtProduct.getLineCount() <= 2) {
llStockCountItem.setPadding(0, 0, 0, 10);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.WRAP_CONTENT, 7);
params.setMargins(1, 1, 1, 10);
txtProduct.setLayoutParams(params);
}
}
});
return rowView;
}
The margin/padding is applied when the list is scrolled, but not when the list is first displayed or on orientation change.
How can I get it to apply the margin/padding on activity load or orientation change?
Handling Runtime Changes
When Screen orientation such a change occurs, Android restarts the running Activity (onDestroy() is called, followed by onCreate()). The restart behavior is designed to help your application adapt to new configurations by automatically reloading your application with alternative resources that match the new device configuration.
To properly handle a restart, it is important that your activity restores its previous state through the normal Activity lifecycle, in which Android calls onSaveInstanceState() before it destroys your activity so that you can save data about the application state. You can then restore the state during onCreate() or onRestoreInstanceState().
http://developer.android.com/guide/topics/resources/runtime-changes.html
GRAVITY
in code
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(0,
LinearLayout.LayoutParams.WRAP_CONTENT, 7);
params.setMargins(1, 1, 1, 10);
params.gravity = Gravity.FILL; // this is where i come in
txtProduct.setLayoutParams(params);
txtProduct.invalidate(); // edits
txtProduct.requestLayout();//edits
the type of Gravity is up to you now with rotation you need to override onOnrientationChanged() (something like that) and call that same code there
Edit
base on your post runnable code i am thinking of a workaround, i do not think it will work but worth it.. since txtProduct.getLineCount() returns 0 after layout pass, i am improvising
if(txtProduct.getLineCount()==0){ //if false you run your previous code without post
int textSize = txtProduct.getTextSize()/2,mw,lines;
// for the textsize i am thinking of a rectangle
if(txtProduct.getMeasuredWidth() > 0) //if this line checks out 0 the code is trash
//assume none where zero
int fillW = textSize * txtProduct.getText().toString().length();
if(fillW > mw){ //my logic here is we have more than one line
if(fillW / mw > -1){ //
lines = fillW/mv;
if(fillW%mv !=0){// it is not a factor which means there is another line trending
lines++;
// now add your normal code here without post to check if lines is what you want
}
}
}
}else{ //add your code without post
see if this works,

How do I fit an exact number of ListView items on screen?

I would like the rows in a ListView to be sized so that exactly six of them can fit on the screen. For that, I would need to know how much vertical space is available to the ListView (not the whole screen). However, no measuring can be done in onCreate() since no views have been rendered yet.
If I make measurements after rendering, the ListView might be drawn and then resized, which may be distracting. What is the smartest way to establish the necessary row height before rendering the ListView?
in onCreate you can get the height of your screen and divide by 6.
Now in your getView you get the reference of the top layout for each item, suppost you have named it's id to root and i.e it's a LinearLayout.
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
if(view == null){ some inflate }
LinearLayout root = (LinearLayout) view.findViewById(R.id.root);
LayoutParams lp = root.getLayoutParams();
lp.height = screenHeight/6;
root.setLayoutParams(lp);
....
return view;
}
Yes, this assumes the ListView is in fullscreen.
If you have other layouts, you will have to get those height into account.
Then your height will be: int heightForEachItem = (screenHeight - otherlayoutsHeightTogether) / 6;
Turns out that the earliest you can measure a ListView is in the onGlobalLayout() callback.
Here is my example.
params = new AbsListView.LayoutParams(-1,-1);
listview.getViewTreeObserver.addOnGlobalLayoutListener(new OnGlobalLayoutListener(){
#Override
public void onGlobalLayout(){ //this is called just before rendering
params.height = listview.getHeight()/6; // this is what I was looking for
listview.getViewTreeObserver.removeOnGlobalLayoutListener(this); // this is called very often
}
adapter = new ArrayAdapter<...>(int position, ...){
#Override
public View getView(...){
LinearLayout item = new LinearLayout(context);
item.setLayoutParams(params);
// add text, images etc with getItem(position) and item.addView(View)
return item;
}
}
listview.setAdapter(adapter);

Android GridView Custom Adapter only ever displays a single row

I am working on a ListView with items that can expand to show a GridView. The ListView and adapter work fine, and the GridView expands fine when added, but I cannot get it to display more than a single row in the grid. There is only ever a single column displayed, no matter the length I set the column to, and it's clear that the issue isn't that the view is just too small (I have tried making it have an absurdly large height). I've browsed other questions here but this doesn't seem to be a common problem. What am I doing wrong?
xml:
<?xml version="1.0" encoding="utf-8"?>
<GridView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/scorecardGridView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:columnWidth="25dp"
android:numColumns="18"
android:isScrollContainer="false"
android:verticalSpacing="5dp"
android:horizontalSpacing="5dp"
android:stretchMode="columnWidth"
android:gravity="center" />
GridAdapter getView() code:
public View getView(int position, View convertView, ViewGroup parent) {
Log.d("position",String.valueOf(position));
TextView textView;
if (convertView == null) { // if it's not recycled, initialize some
// attributes
textView = new TextView(context);
textView.setLayoutParams(new GridView.LayoutParams(25, 25));
} else {
textView = (TextView) convertView;
}
if (position < 18)
textView.setText(String.valueOf(position+1));
else {
position -= 18;
textView.setTypeface(null, Typeface.BOLD);
if (scores[position] > 0) {
textView.setTextColor(context.getResources().getColor(
R.color.red));
textView.setText("+" + String.valueOf(scores[position]));
} else {
if (scores[position] < 0)
textView.setTextColor(context.getResources().getColor(
R.color.blue));
textView.setText(String.valueOf(scores[position]));
}
}
return textView;
}
I am using this to show a two row, 18 column golf scorecard. No matter what I do, only the first row shows. If I change the numColumns attribute, that new number of columns shows, but always just one row. You can see I tried Logging the positions for which getView() is being called, and it is revealing that it is only being called for the first row.
Let me know if you want to see any other code, thanks.

Categories

Resources