I'm calling this method that should redraw a pointer in the position given in every call.
ImageView ivPointer=null;
public void moveCursor(Bitmap bmPuntero, int x, int y)
{
RelativeLayout rl = (RelativeLayout) findViewById(R.id.gamelayout);
if (ivPointer!=null)
rl.removeView(ivPointer);
ivPointer = new ImageView(this);
ivPointer.setImageBitmap(bmPuntero);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(65, 65);
params.leftMargin = x;
params.topMargin = y;
rl.addView(ivPointer, params);
}
The result is that the bitmap isn't showed. If I remove the lines that remove the view, I see how the bitmap is drawn multiple times, so the add part should be correct.
Try this:
{
// Somewhere (in onCreate of the Activity for example):
RelativeLayout rl = (RelativeLayout) findViewById(R.id.gamelayout);
ImageView ivPointer = initPointer(this, bmPuntero); // Get image from somewhere
rl.addView(ivPointer);
}
// To update the cursor's po
public static void moveCursor(ImageView pointer, int x, int y) {
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) pointer.getLayoutParams();
params.leftMargin = x;
params.topMargin = y;
pointer.setLayoutParams(params);
pointer.requestLayout(); // Refresh the layout
}
// Call this method to initialise the pointer (in onCreate of your Activity
// for example)
public static ImageView initPointer(Context context, Bitmap bmp) {
// Define the LayoutParams
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(65, 65);
params.leftMargin = DEFAULT_POS_X; // TODO: Constants to be defined
params.topMargin = DEFAULT_POS_Y;
// Init the ImageView
ImageView pointer = new ImageView(context);
pointer.setImageBitmap(bmp);
pointer.setLayoutParams(params);
return pointer;
}
Related
I've created a RelativeLayout within my activity, and I'm dynamically creating ImageView objects that I'm adding to the RelativeLayout using addView along with RelativeLayout.LayoutParams. When I then go to get the position of the child view, it always returns the coordinates of the parent view. Here are the pertinent parts of the code:
public class MainActivity extends AppCompatActivity {
public RelativeLayout parentLayout;
RelativeLayout.LayoutParams layoutParams;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
parentLayout = findViewById(R.id.parentRelativeLayout);
}
// Method to dynamically add the ImageView to the parent
public int addObject(Drawable drawing, int x, int y) {
ImageView newObj = new ImageView(getApplicationContext());
newObj.setBackground(drawing);
layoutParams = new RelativeLayout.LayoutParams(50, 50);
layoutParams.leftMargin = x;
layoutParams.topMargin = y;
int childIndex = parentLayout.getChildCount()-1;
parentLayout.addView(newObj, childIndex,layoutParams);
return childIndex;
}
public int[] getChildLocation(int childIndex) {
View childView;
int[] outlineCoord = new int[2];
childView = parentLayout.getChildAt(childIndex);
childView.getLocationOnScreen(outlineCoord);
return outlineCoord;
}
}
If I then add a child and attempt to retrieve the coordinates of the child view, I always get the location of the parent:
childIndex = addObject(getResources().getDrawable(blackcircle), 100, 200);
outlineCoord = getChildLocation(childIndex);
Log.i("LOC:", "Location of child is X: " + outlineCoord[0] + " Y: " + outlineCoord[1]);
I can't quite figure out what I'm doing wrong here.
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 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 :)
I have CustomView which is just an arc shape with some lines.
public class CustomDrawableView extends View {
private ShapeDrawable mDrawable;
private Paint paint = new Paint();
public CustomDrawableView(Context context, int startA, int endA) {
super(context);
int x = 0;
int y = 0;
int width = 400;
int height = 400;
paint.setColor(Color.BLACK);
mDrawable = new ShapeDrawable(new ArcShape(startA, endA));
mDrawable.getPaint().setColor(0xff74AC23);
mDrawable.setBounds(x, y, x + width, y + height);
}
protected void onDraw(Canvas canvas) {
mDrawable.draw(canvas);
canvas.drawLine(0,0,400,0,paint);
canvas.drawLine(0, 0, 0, 400, paint);
canvas.drawLine(400,0, 400,400, paint);
}
}
Afterward I call out my linear layout from the xml file through its id add a framelayout to it. After that, I add CustomDrawableView and try to center it by using gravity. I went through many other questions and tried those solutions, but it just doesn't work for me. If it's worth noting, I notice when I use a regular view like a textview with no custom view in my layout, it centers perfectly.
public class MainActivity extends ActionBarActivity {
private RelativeLayout ll;
private CustomDrawableView testView;
private RelativeLayout.LayoutParams layout;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// load the layout
LinearLayout linLayout = (LinearLayout)findViewById(R.id.ll);
linLayout.setOrientation(LinearLayout.VERTICAL);
/******** Experimental Code **********/
RelativeLayout rl = new RelativeLayout(this);
linLayout.addView(rl);
LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT);
CustomDrawableView arc = new CustomDrawableView(this,0,30);
CustomDrawableView arcTwo = new CustomDrawableView(this, 50, 30);
rl.setGravity(Gravity.CENTER_HORIZONTAL);
rl.addView(arc, lp);
rl.addView(arcTwo, lp);
rl.setBackgroundColor(Color.GRAY); }
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
I use the frame layout in so i can lay views over each other.
There are a few problems here.
First is that you need set the layout params for your RelativeLayout called "rl" when you add it to your LinearLayout called "linLayout." Do this with the following code:
RelativeLayout rl = new RelativeLayout(this);
LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
linLayout.addView(rl, params);
Your other issue is that when you add your customViews to rl it is better to add a rule to the layout params than to use gravity. The code below demonstrates this:
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
lp.addRule(RelativeLayout.CENTER_IN_PARENT);
CustomDrawableView arc = new CustomDrawableView(this,0,30);
CustomDrawableView arcTwo = new CustomDrawableView(this, 50, 30);
rl.addView(arc, lp);
rl.addView(arcTwo, lp);
Hope this helps!
Have you try to set rl's layout_width and layout_height to match_parent?
Try this code
/******** Experimental Code **********/
RelativeLayout rl = new RelativeLayout(this);
LayoutParams parems = new LayoutParams(LayoutParams.MATH_PARENT,
LayoutParams.MATH_PARENT);
rl.setParameters(parems);
linLayout.addView(rl);
UPDATE :
Please show your activity_main.xml code and notice your api level. If so, I'm going to run your code.
Otherwise, have you try to set layout size from onMeasure()?
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = 0;
switch (heightMode) {
case MeasureSpec.AT_MOST: // wrap_confent
heightSize = 400;
break;
case MeasureSpec.EXACTLY: // match_parent
heightSize = MeasureSpec.getSize(heightMeasureSpec);
break;
}
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = 0;
switch (widthMode) {
case MeasureSpec.AT_MOST: // wrap_confent
widthSize = 400;
break;
case MeasureSpec.EXACTLY: // match_parent
widthSize = MeasureSpec.getSize(widthMeasureSpec);
break;
}
setMeasuredDimension(widthSize, heightSize);
}
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();
}
});