I am new to Android Development. I have been working with using a GridLayout to display Dynamically inserted ImageViews.
My issue is located in "onFocusWindowChanged" but I pasted my onCreate where I do my assignments of the images.
private List<Behavior> behaviors = null;
private static int NUM_OF_COLUMNS = 2;
private List<ImageView> images;
private GridLayout grid;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_behaviors);
XMLPullParserHandler parser = new XMLPullParserHandler();
try {
behaviors = parser.parse(getAssets().open("catagories.xml"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
grid = (GridLayout) findViewById(R.id.behaviorGrid);
images = new ArrayList<ImageView>();
grid.setColumnCount(NUM_OF_COLUMNS);
grid.setRowCount(behaviors.size() / NUM_OF_COLUMNS);
for (Behavior behavior : behaviors)
images.add(this.getImageViewFromName(behavior.getName()));
}
#Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
View view = (View) findViewById(R.id.scrollView);
int width = (int) (view.getWidth() * .45);
Log.i("ViewWidth", Integer.toString(width));
GridLayout.LayoutParams lp = new GridLayout.LayoutParams();
lp.height = width;
lp.width = width;
int childCount = images.size();
ImageView image;
for (int i = 0; i < childCount-1; i++) {
image = images.get(i);
image.setLayoutParams(lp);
grid.addView(image);
}
}
In my (short) previous experience, using
grid.add(View);
worked fine, but now I am only seeing the last child display only. Looking through the debugger I can see that the gridview is being populated with more than just the last element, as well as the last imageview.
Thank you for your help
you should create a GridLayout.LayoutParams for each ImageView:
for (int i = 0; i < childCount-1; i++) {
GridLayout.LayoutParams lp = new GridLayout.LayoutParams();
lp.height = width;
lp.width = width;
......
}
GridLayout.LayoutParams contains location information, e.g [column:2, row:3]. In your code, all ImageViews are set the same GridLayout.LayoutParams, so they are located in the same cell(overlapping each other).
When use LinearLayout.LayoutParams instead, there is no location information in it. GridLayout will create a new GridLayout.LayoutParams for each child view, so all ImageViews use their own different GridLayout.LayoutParams and location.
Wish this help. You can read the GridLayout.java and ViewGroup.java for more details.
So I solved my issue, although I'm not sure how-
GridLayout.LayoutParams lp = new GridLayout.LayoutParams();
changed to...
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(x,y);
made it work just as I wanted it. But I'm not sure why- If anyone could explain, please do :)
Related
I want to add new child views after every 50 pixels of scrolling but the statement Log.d("scroll",scrollY+":"+oldScrollY); is missing some values i.e. scrollY = 149 and scrollY = 151 are there in Log but scrollY = 150 is missing. So the code doesn't run for scrollY = 150 and new child views is not added.
Although it works as it should for most of the values of scrollY but for few values of scrollY, the event is not being triggered.
How can i resolve this issue? Or is there any other way to achieve this.
public class MainActivity extends AppCompatActivity implements ScrollViewListener {
RelativeLayout parent;
TextView height;
ObservableScrollView scrollView;
int position=1;
View view1,view2;
#RequiresApi(api = Build.VERSION_CODES.M)
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
parent = (RelativeLayout) findViewById(R.id.parent);
scrollView = (ObservableScrollView) findViewById(R.id.scroll_view);
LayoutInflater inflater = LayoutInflater.from(this);
view1 = inflater.inflate(R.layout.education,null, false);
view1.setId(R.id.parent+position);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
params.addRule(RelativeLayout.LEFT_OF,R.id.divider);
params.topMargin = 100;
params.rightMargin = 3;
parent.addView(view1, params);
position++;
final Animation leftAnimation = new TranslateAnimation(view1.getX()-50,view1.getX(),view1.getY()+100,view1.getY());
leftAnimation.setDuration(1000);
view1.setAnimation(leftAnimation);
scrollView.setOnScrollChangeListener(new View.OnScrollChangeListener() {
#Override
public void onScrollChange(View view, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
Log.d("scroll",scrollY+":"+oldScrollY);
if((scrollY-oldScrollY)>0 && scrollY%50 == 0)
{
Log.d("scroll","abcghfg");
if(position%2==0)
{
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
params.addRule(RelativeLayout.RIGHT_OF,R.id.divider);
// params.topMargin = (position-1)*(view1.getLayoutParams().height)+position*100;
params.topMargin = 30;
params.leftMargin = 3;
params.addRule(RelativeLayout.BELOW,parent.getChildAt(position-1).getId());
Log.d("scroll","abc");
view2 = LayoutInflater.from(MainActivity.this).inflate(R.layout.education,null,false);
view2.setId(R.id.parent+position);
Animation rightAimation = new TranslateAnimation(view2.getX()+50,view2.getX(),view2.getY()+100,view2.getY());
rightAimation.setDuration(1000);
view2.startAnimation(rightAimation);
parent.addView(view2, params);
}
else
{
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
params.addRule(RelativeLayout.LEFT_OF,R.id.divider);
//params.topMargin = (position-1)*(view1.getLayoutParams().height)+position*100;
params.topMargin = 30;
params.rightMargin = 3;
params.addRule(RelativeLayout.BELOW,parent.getChildAt(position-1).getId());
Log.d("scroll","def");
view2 = LayoutInflater.from(MainActivity.this).inflate(R.layout.education,null,false);
view2.setId(R.id.parent+position);
Animation animation = new TranslateAnimation(view2.getX()-50,view2.getX(),view2.getY()+100,view2.getY());
animation.setDuration(1000);
view2.startAnimation(animation);
parent.addView(view2, params);
}
position++;
}
}
});
}
}
Thanks in advance.
Android doesn't render every pixel in a scroll, because it would be bad for performance. If you scroll really slow, you will see that your callback will be called for every pixel, but if you scroll fast, it will be called just when the render triggers.
In your case, you need to check if it rendered 50 or more pixels since last time you rendered the last view.
I am working in Android studio and using TableLayout. i want to display small imageButtons. and height of each button can be changed programmatically. I tried my best. but does not change the height of imageButton, Please anyone help me, what changes can i make in this code. thanks
public void settable() {
index = 0;
LinearLayout le = (LinearLayout) findViewById(R.id.onofffbutton);
float height = le.getHeight();
height= height/9.0f;
for (int a = 0; a < maxrow; a++) {
TableRow row = new TableRow(this);
for (int b = 0; b < col; b++) {
location[a][b] = new ImageView(this);
/*LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(50, 50);
location[a][b].setLayoutParams(layoutParams);*/
if (isOn[a][b]) {
location[a][b].setBackgroundResource(R.drawable.box1);
} else {
location[a][b].setBackgroundResource(R.drawable.box);
}
location[a][b].setMaxHeight(height);
location[a][b].setOnClickListener(Onclick);
location[a][b].setId(index++);
row.addView(location[a][b]);
}
tableLayout.addView(row, a);
}
}
Why when I add the elements to the FrameLayout flCatScroll only one shows and not ten are they perhaps overlapping and or why dosn't the margin increase.
myactivity.runOnUiThread(new Runnable() {
#Override
public void run() {
//Main Framelayout
FrameLayout flCatScroll = (FrameLayout) myactivity.findViewById(R.id.flCatScroll);
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
params.gravity = Gravity.TOP;
params.topMargin = 20;
for(int i = 0; i < 10; i++) {
//FrameLayout mainItemLayout = new FrameLayout(myactivity);
listFramelayouts.add(new FrameLayout(myactivity));
}
for(int i = 0; i < listFramelayouts.size(); i++) {
params.topMargin = 20 * i;
TextView itemName = new TextView(myactivity);
itemName.setText("Test" + i);
listFramelayouts.get(i).addView(itemName);
flCatScroll.addView(listFramelayouts.get(i), params);
}
}
});
Reference semantics strike again!
Because you're reusing the params object instead of creating a new one each time, They all share the same margin at the end regardless of what the margin was when you added the view. So they are, indeed, all overlapping.
Does this make sense?
dcow is right. You are reusing the same LayoutParams object for each new TextView. So at the end all of them have the same topMargin. You need to create params per each new view. You can add new function like:
private FrameLayout.LayoutParams getLayoutParamsFor(final int i) {
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
params.gravity = Gravity.TOP;
params.topMargin = 20 * i;
return params;
}
and then inside your loop you call it in addView(...) call:
flCatScroll.addView(listFramelayouts.get(i), getLayoutParamsFor(i));
I'm playing around in Android and what I'm trying to achieve is a 10x10tile boardgame.
I want to read size and width of screen and then I want a square in the middle with a textViews above and below.
This is what I've done so far:
public void init(){
Point size = new Point();
WindowManager w = getWindowManager();
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
w.getDefaultDisplay().getSize(size);
screenWidth = size.x;
screenHeight = size.y;
}else{
Display d = w.getDefaultDisplay();
screenWidth = d.getWidth();
screenHeight = d.getHeight();
}
LinearLayout linearLayout = (LinearLayout) findViewById(R.id.LinearLayout);
linearLayout.setOrientation(LinearLayout.VERTICAL);
TextView TVtop = new TextView(this.getApplicationContext());
TVtop.setHeight((screenHeight-screenWidth)/2);
TVtop.setWidth(screenWidth);
TVtop.setText("TOP");
TextView TVbot = new TextView(this.getApplicationContext());
TVbot.setHeight((screenHeight-screenWidth)/2);
TVbot.setWidth(screenWidth);
TVbot.setText("BOT");
TableLayout tableLayout = new TableLayout(this.getApplicationContext());
//Make a cube
LayoutParams tableParams = new LayoutParams(screenWidth, screenWidth);
tableLayout.setLayoutParams(tableParams);
//Populate tableLayout
for(int i = 0; i < nrOfTiles; i++){
TableRow tableRow = new TableRow(this.getApplicationContext());
for(int j = 0; j < nrOfTiles; j++){
ImageView imgView = new ImageView(this.getApplicationContext());
imgView.setImageResource(R.drawable.cell);
tableRow.addView(imgView);
}
tableLayout.addView(tableRow);
}
linearLayout.addView(TVtop);
linearLayout.addView(tableLayout);
linearLayout.addView(TVbot);
}
}
I've tried diffrent layoutparams but nothing seems to get the work done. :S
BR
Personally, I would use a RelativeLayout and setMargins for the items.
While not a direct answer to your question, the following code will display 15 icons in three rows. This should be enough to explain and get you started.
The main activity.
public class MainActivity extends Activity {
private int mWidth;
private int mTile;
private int mColMax = 5;
private Context mContext;
#SuppressWarnings("deprecation")
#SuppressLint("NewApi")
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mContext = this;
// the screen width is need to work out the tile size
WindowManager w = getWindowManager();
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
Point size = new Point();
w.getDefaultDisplay().getSize(size);
mWidth = size.x;
}else{
mWidth = w.getDefaultDisplay().getWidth();
}
// how wide (and high) each icon will be to fit the screen.
mTile = (mWidth / mColMax);
setContentView(R.layout.activity_main);
// layout the icons
initUI();
}
/**
* Layout 15 icon images in three rows dynamically.
*/
private void initUI() {
// this is the layout from the XML
ViewGroup layout = (ViewGroup) findViewById(R.id.main_layout);
ImageView iv;
RelativeLayout.LayoutParams params;
int i = 0;
int row = 0;
int col = 0;
do {
params = new RelativeLayout.LayoutParams(mTile,mTile);
params.setMargins((col * mTile), (row * mTile), 0, 0);
iv = new ImageView(mContext);
iv.setAdjustViewBounds(true);
iv.setScaleType(ScaleType.FIT_CENTER);
iv.setImageResource(R.drawable.ic_launcher);
iv.setLayoutParams(params);
layout.addView(iv);
if (col == mColMax) {
row++;
col = 0;
} else {
col++;
}
} while (++i <= 16);
}
}
And the layout XML.
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/main_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
</RelativeLayout>
I have TextView created programmatically, like that:
TextView mTextView = new TextView(getApplicationContext());
final LayoutParams params = new TableLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
((MarginLayoutParams) params).setMargins(8, 8, 0, 0);
mTextView.setText(mText);
mTextView.setLayoutParams(params);
mTextView.setPadding(2, 2, 2, 2);
mTextView.setBackground(getResources().getDrawable(R.drawable.note_corps));
tagMap.addView(mTextView);
textViewsWidth = mTextView.getWidth();
But mTextView.getWidth() always returns 0
And if I try:
mTextView.getLayoutParams().width
It returns the LayoutParams corresponding value in the LayoutParams class (-1 or -2)
How can I get the view's width ?
EDIT I need to do this here:
#Override
public void onPostExecute(Hashtable<String, Integer> hash){
final ScrollView tagMapScroll = (ScrollView) findViewById(R.id.tagMapScroll);
final LinearLayout tagMap = (LinearLayout) findViewById(R.id.tagMap);
final ArrayList<Integer> arr = new ArrayList<Integer>(hash.values());
final Enumeration<String> e = hash.keys();
int index = 0;
int textViewsWidth = 0;
while(e.hasMoreElements()){
final TextView tV = new TextView(getApplicationContext());
tV.setTextColor(Color.parseColor("#666666"));
tV.setText(Html.fromHtml(randomColor() + e.nextElement()));
tV.setTextSize(arr.get(index));
final LayoutParams params = new TableLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
((MarginLayoutParams) params).setMargins(8, 8, 0, 0);
tV.setLayoutParams(params);
tV.setPadding(2, 2, 2, 2);
tV.setBackground(getResources().getDrawable(R.drawable.note_corps));
tagMap.addView(tV);
textViewsWidth += tV.getWidth();
index++;
}
tagMapScroll.setVisibility(ScrollView.VISIBLE);
}
EDIT SOLUTION I used this from #androiduser's answer:
mTextView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
int width = mTextView.getMeasuredWidth();
int height = mTextView.getMeasuredHeight();
Problem solved !
I used this solution:
yourView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
// Ensure you call it only once
yourView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
// Here you can get the size :)
}
});
get this way:
tV.post(new Runnable() {
#Override
public void run() {
int width=tV.getMeasuredWidth();
}
});
those values are constant value for FILL_PARENT and WRAP_CONTENT. If you want to check the view size you can try this way:
tagMap.addView(mTextView);
tagMap.post(new Runnable() {
#Override
public void run() {
mTextView. getWidth();
}
});
you have to wait until android draws the TextView. This way you are posting a Runnable in the tagMap queue, that is executed, hopefully after the textview is draw (so it should be weight and height)
In this method you can get the width height of the view..
#Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
int width = mTextView.getWidth();
int height = mTextView.getHeight();
}
and define TextView mTextView as global
You have to use ViewTreeObserver class which is used to register listeners that can be notified of global changes in the view tree. Such global events include, but are not limited to, layout of the whole tree, beginning of the drawing pass, touch mode change.
In the Activity's onCreate mehotd put this:
ViewTreeObserver vto = mTextView.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
mTextView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
int viewWidth = mTextView.getMeasuredWidth();
}
});