I am using OnGlobalLayoutListener. How can I use data from this listener? Especially I need lAngle.
past_edittext.getViewTreeObserver().addOnGlobalLayoutListener(
new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
int height = past_edittext.getHeight();
int width = past_edittext.getWidth();
int top = past_edittext.getTop();
int left = past_edittext.getLeft();
// center coordinates of EditText
past_edittextX = left + width / 2;
past_edittextY = top + height / 2;
lAngle = (float) (Math
.atan((totalCenterY - past_edittextY)
/ (totalCenterX - past_edittextX)) * 180 / Math.PI);
}
});
in your class declare the following
private float lAngle;
then you can access lAngle after you've set it from the globallayoutlistener
...
past_edittext.getViewTreeObserver().addOnGlobalLayoutListener(
new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
int height = past_edittext.getHeight();
int width = past_edittext.getWidth();
int top = past_edittext.getTop();
int left = past_edittext.getLeft();
// center coordinates of EditText
past_edittextX = left + width / 2;
past_edittextY = top + height / 2;
lAngle = (float) (Math
.atan((totalCenterY - past_edittextY)
/ (totalCenterX - past_edittextX)) * 180 / Math.PI);
}
});
}
public void someOtherMethod(){
if (lAngle != null)
// do something...
Related
I have a custom view inside a NestedScrollView. Every time invalidate is called on the view, the layout scrolls to top of the custom view. I want the scroll position to be unchanged after the view has been redrawn. Any idea how this can be done?
I have tried implementing an onScrollChangeListener and onGlobalLayoutListener in combination to rescroll to the previously scrolled position, but it doesn't work. I have the following code in the onCreateView method of a fragment.
ViewTreeObserver observer = layoutView.getViewTreeObserver();
if (scrollListener != null) {
observer.removeOnScrollChangedListener(scrollListener);
} else {
scrollListener = new ViewTreeObserver.OnScrollChangedListener() {
#Override
public void onScrollChanged() {
scrollX = layoutView.getScrollX();
scrollY = layoutView.getScrollY();
}
};
}
observer.addOnScrollChangedListener(scrollListener);
if (layoutListener != null) {
observer.removeOnGlobalLayoutListener(layoutListener);
} else {
layoutListener = new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
if (customView != null && scrollY != 0 && getUserVisibleHint()) {
layoutView.setVerticalScrollbarPosition(scrollY);
}
};
}
observer.addOnGlobalLayoutListener(layoutListener);
The following is the code for the onDraw and onMeasure method of the custom view.
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (pieces == null) {
return;
}
int position = 0;
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols && position < pieces.length; c++) {
Paint paint = (pieces[position] ? complete : empty);
int left = c * stepSize + borderSize + margin;
int right = left + stepSize - borderSize * 2;
int top = r * stepSize + borderSize;
int bottom = top + stepSize - borderSize * 2;
canvas.drawRect(left + borderSize, top + borderSize,
right + borderSize, bottom + borderSize, paint);
++position;
}
}
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = MeasureSpec.getSize(widthMeasureSpec) - getPaddingLeft() - getPaddingRight();
cols = width / stepSize;
rows = (int) Math.ceil((float) cells / (float) cols);
margin = (width - cols * stepSize) / 2;
int height = rows * stepSize;
setMeasuredDimension(width, Math.max(width, height));
}
I want to show 3x3 sized gridview. I want to set the height and width based on device size. I am taking reference from this link.
MainActivity-
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
GridView gridview = (GridView) findViewById(R.id.gridview);
gridview.setAdapter(new ImageAdapter(this));
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
activity_main-
<?xml version="1.0" encoding="utf-8"?>
<GridView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/gridview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:columnWidth="90dp"
android:numColumns="auto_fit"
android:verticalSpacing="10dp"
android:horizontalSpacing="10dp"
android:stretchMode="columnWidth"
android:gravity="center"
/>
Edit-
Like first getting screen height and width then each item height and width 1/3 of the value of screen height and width I am getting.
Do not use screen size, in a multi-windows context this method is invalid.
If your grid is a 3x3 items size fixed, so use custom layout ViewGroup like this: (and set RelativeLayout items content)
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle state) {
setContentView(new ViewGroup(this) {
private RelativeLayout[] items = new RelativeLayout[9];
private int width, height, itemWidth, itemHeight;
{
Random r = new Random();
for (int i = 0; i < 9; i++) {
items[i] = new RelativeLayout(getContext());
float[] hsv = new float[] {360 * r.nextFloat(), .50f, .75f};
items[i].setBackgroundColor(Color.HSVToColor(hsv));
addView(items[i]);
// UPDATE ////////////////////////////////////
ImageView image = new ImageView(getContext());
switch (i) {
case 0: // top left
case 1: // top center
case 2: // top right
case 3: // center left
case 4: // center center
case 5: // center right
case 6: // bottom left
case 7: // bottom center
case 8: // bottom right
image.setImageResource(R.drawable.ic_launcher);
break;
}
image.setScaleType(ScaleType.FIT_XY);
image.setLayoutParams(new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.MATCH_PARENT,
RelativeLayout.LayoutParams.MATCH_PARENT
));
items[i].addView(image);
//////////////////////////////////////////////
}
}
#Override
protected void onMeasure(int wMS, int hMS) {
width = MeasureSpec.getSize(wMS);
height = MeasureSpec.getSize(hMS);
itemWidth = width / 3;
itemHeight = height / 3;
wMS = MeasureSpec.makeMeasureSpec(itemWidth, MeasureSpec.EXACTLY);
hMS = MeasureSpec.makeMeasureSpec(itemHeight, MeasureSpec.EXACTLY);
measureChildren(wMS, hMS);
setMeasuredDimension(width, height);
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
for (int i = 0; i < 9; i++) {
l = itemWidth * (i % 3);
t = itemHeight * (i / 3);
r = l + itemWidth;
b = t + itemHeight;
items[i].layout(l, t, r, b);
}
}
});
super.onCreate(state);
}
}
EDIT : see my update in code, you have simply to add your images to the items containers. With this method, no XML layout file needed because you manage content and size yourself.
Result :
EDIT : the minimalist way:
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle state) {
setContentView(new ViewGroup(this) {
private static final int SIZE_X = 3;
private static final int SIZE_Y = 3;
private ImageView[] items = new ImageView[SIZE_X * SIZE_Y];
private int itemWidth, itemHeight;
{
setBackgroundColor(Color.DKGRAY);
for (int i = 0; i < items.length; i++) {
items[i] = new ImageView(getContext());
items[i].setScaleType(ScaleType.CENTER);
items[i].setImageResource(R.drawable.ic_launcher);
addView(items[i]);
}
}
#Override
protected void onMeasure(int wMS, int hMS) {
int width = MeasureSpec.getSize(wMS);
int height = MeasureSpec.getSize(hMS);
itemWidth = width / SIZE_X;
itemHeight = height / SIZE_Y;
wMS = MeasureSpec.makeMeasureSpec(itemWidth, MeasureSpec.EXACTLY);
hMS = MeasureSpec.makeMeasureSpec(itemHeight, MeasureSpec.EXACTLY);
measureChildren(wMS, hMS);
setMeasuredDimension(width, height);
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
for (int i = 0; i < items.length; i++) {
l = itemWidth * (i % SIZE_X);
t = itemHeight * (i / SIZE_X);
r = l + itemWidth;
b = t + itemHeight;
items[i].layout(l, t, r, b);
}
}
});
super.onCreate(state);
}
}
Result :
# Kanwaljit Singh:
In MainActivity items creation loop:
final int id = i;
items[i].setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
startActivity(new Intent(getContext(), NextActivity.class).putExtra("id", id));
}
});
In NextActivity:
int id = getIntent().getIntExtra("id", -1);
You can get the screen dimensions like:
final DisplayMetrics displayMetrics=getResources().getDisplayMetrics();
final float screenWidthInDp=displayMetrics.widthPixels;
Log.WTF("ScreenWidth", "width: "+screenWidthInDp+", menuWidth: "+screenWidthInDp/3);
And for the gridview, I would suggest you to take a look at this awesome library called Staggered Grid View. And their sample here.
I use the following approach when I have to resize my Activitys, I assume the same is valid for your case:
// I'm storing the size of the window in the display var, so I can then play around
final Display display = getWindowManager().getDefaultDisplay();
final Point size = new Point();
display.getSize(size);
// In your case, you'll probably need something like this:
GridView gv = (GridView) findViewById(R.id.gridview);
gv.setWidth((int) size.x * 0.75); // Whis would resize the grid width to the 75%
gv.setHeight((int) size.y * 0.5); // Same with the height, but to the 50%
When I click the button,call drawDigit(),puzzleview is only a LinearLayout in Activity
protected void drawDigit(Canvas canvas, int digit) {
// TODO Auto-generated method stub
if(num < diff){
int x = tiles.get(num).getScrollX(); // get the X coordinate of ImageView,it's 0
int y = tiles.get(num).getScrollY(); // get the Y coordinate of ImageView,it's 0
float height = tiles.get(num).getHeight(); // height is 0
float width = tiles.get(num).getWidth(); // width is 0
background.setTextSize(height * 0.75f);
background.setStyle(Style.FILL);
background.setTextScaleX(width/height);
background.setTextAlign(Paint.Align.CENTER);
canvas.drawText(digit + "", x, y, background);
//num++;
}
}
How can I assign the ImageView in Layout to tiles,then get the coordinate and size?
You can try this :
//This is for Getting ImageView size that is fixed in layout
int imageHeight;
int imageWidth;
ImageView imageViewObj = (ImageView)findViewById(R.id.image_view_id);
ViewTreeObserver treeObsObj = imageViewObj.getViewTreeObserver();
treeObsObj.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
public boolean onPreDraw() {
imageWidth= imageViewObj.getMeasuredWidth();
imageHeight = imageViewObj.getMeasuredHeight();
return true;
}
});
// Getting the size of the Image inside the ImageView and The size will differ based
**// on the image you placed inside the ImageView
ImageView imageObj = (ImageView)findViewById(R.id.image_view_id);
int imageWidth = imageObj.getWidth();
int imageHeight = imageObj.getHeight();
I am using a View extended from View group and the onDraw is not getting called when I call invalidate.Can any one please explain?
The code is given below
public class BarGraph extends View {
private int viewHeight;
private int viewWidth; // height and width of bar graph dynamically calculated.
private int mGraphColor; // the colour of the bar graph.
private ArrayList<Integer> mTodays; // The array list that handles the input to draw the graph.
private final int barCount = 20; // Number of bars in the bar graph...here set as 20.
/*
* The maximum action value a bar can take.
* This is calculated based on the action array
* passed to the chart.
*/
private int yMax = 0;
private Paint graphColor;
public BarGraph(Context context, int graphColor) {
super(context);
this.setWillNotDraw(false);
mGraphColor = graphColor;
setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
initializePaintObjects();
}
public BarGraph(Context context, AttributeSet attrs) {
super(context, attrs);
this.setWillNotDraw(false);
initializePaintObjects();
}
private void initializePaintObjects(){
graphColor = new Paint();
graphColor.setColor(mGraphColor);
graphColor.setStyle(Style.FILL);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if(mTodays == null) // If the array list is empty.
return;
if(yMax <= 0)
return;
int left = 0;
viewHeight = getHeight();
viewWidth = getWidth();
if((viewWidth % barCount) > 0){ //adjusting the view width so that bars correctly fits in
int newWidth = (int) (Math.floor(viewWidth / barCount) * barCount);
left = (int) Math.floor(((viewWidth - newWidth)/2));
viewWidth = (int) Math.floor((viewWidth / barCount) * barCount);
}
int columnWidth = 2;
columnWidth = (int) Math.floor(viewWidth / barCount);
int xFactor = 1;
xFactor = (int) Math.ceil(columnWidth * 0.33);
int barWidth = 1;
barWidth = columnWidth - xFactor;
graphColor.setStrokeWidth(barWidth);
int j = 0;
for(int i = 0; i < mTodays.size() ; i++){
int todayValue = mTodays.get(i);
float todaysHeight;
if(todayValue == 0){
todaysHeight = (float) (viewHeight-viewHeight*(.001));
}else{
todaysHeight = getYValue(todayValue);
}
canvas.drawLine(((j*columnWidth)+xFactor + left) , viewHeight, ((j*columnWidth)+xFactor + left), todaysHeight, graphColor);
j++;
}
}
public void setData(ArrayList<Integer>todays){
mTodays = todays;
yMax = 0;
for (int val : mTodays){
yMax = yMax > val ? yMax : val;
}
invalidate();
}
private int getYValue(int item){
int percent = (item * 100)/yMax;
return (viewHeight) - ((percent * viewHeight)/100);
}
}
Thanks for all your attempts.The problem was actually in the Main Activity.
The following is the correct code
final Handler handler = new Handler();
Timer timer2 = new Timer();
TimerTask testing = new TimerTask() {
public void run() {
handler.post(new Runnable() {
public void run() {
for(int j=0;j<19;j++){
todays.set(j, todays.get(j+1));
}
Random diceRoller = new Random();
todays.set(19, diceRoller.nextInt(100)*10+1);
MainActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
bargraph.setData(todays);
}
});
}
});
I had not written the runOnUiThread at first...My bad...
When writing in the Textfield, I need my textfield to move upwards in order to let the textfield be visible when the keyboard pops up.
Does libgdx have some kind of method which returns true if the keyboard is visible and false when it is down?
The following code will detect when you press a textfield, prevent it from showing the keyboard and then open a native dialog that moves up and down with the keyboard. It will take the input from the native dialog and finally put it back in your textField:
textField.setOnscreenKeyboard(new TextField.OnscreenKeyboard() {
#Override
public void show(boolean visible) {
//Gdx.input.setOnscreenKeyboardVisible(true);
Gdx.input.getTextInput(new Input.TextInputListener() {
#Override
public void input(String text) {
textField.setText(text);
}
#Override
public void canceled() {
System.out.println("Cancelled.");
}
}, "Title", "Default text...");
}
});
Good Luck!
I know I'm answering to an old thread, but I was googling to find an answer to this question but couldn't find it anywhere. Now I have created a solution myself. Here is how to do it on Android in an elegant way :)
I'm creating an ApplicationBundle to bundle interfaces to add platform specific things. You can do this on iOS too if you want to make use of RoboVM.
My solution:
create a SizeChangeListener interface in the core project:
public interface SizeChangeListener {
public void onSizeChange(float width, float height);
}
create a View interface in the core project:
public interface View {
public void onSizeChange(float width, float height);
public void addListener(SizeChangeListener sizeChangeListener);
public float getWidth();
public float getHeight();
}
create an AndroidView implementing the View interface:
public class AndroidView implements View {
private ArrayList<SizeChangeListener> listeners = new ArrayList<SizeChangeListener>();
private float width, height;
public AndroidView(int width, int height) {
this.width = width;
this.height = height;
}
public void addListener(SizeChangeListener listener) {
listeners.add(listener);
}
public void onSizeChange(float width, float height) {
this.width = width;
this.height = height;
for(SizeChangeListener listener : listeners)
listener.onSizeChange(width, height);
}
public float getWidth() {
return width;
}
public float getHeight() {
return height;
}
}
create an ApplicationBundle in the core project
public class ApplicationBundle {
private final View view;
public ApplicationBundle(View view) {
this.view = view;
}
public View getView() {
return view;
}
}
Make the necessary imports from the core project. In the AndroidLauncher in the Android project add the following:
public class AndroidLauncher extends AndroidApplication {
private View rootView;
private AndroidView androidView;
private int width, height;
#Override
protected void onCreate (Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AndroidApplicationConfiguration config = new AndroidApplicationConfiguration();
rootView = this.getWindow().getDecorView().getRootView();
Rect rect = new Rect();
rootView.getWindowVisibleDisplayFrame(rect);
width = rect.width();
height = rect.height();
androidView = new AndroidView(width, height);
rootView.addOnLayoutChangeListener(new OnLayoutChangeListener() {
#Override
public void onLayoutChange(View v, int left, int top, int right,
int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
Rect rect = new Rect();
rootView.getWindowVisibleDisplayFrame(rect);
if(!(width == rect.width() && height == rect.height())) {
width = rect.width();
height = rect.height();
androidView.onSizeChange(width, height);
}
}
});
initialize(new DigMeApp(new ApplicationBundle(androidView)), config);
}
}
In your main MyApp in the core project in the create() method add a SizeChangeListener implementation to the view you've got from the constructor.
public class MyApp extends Game { // or ApplicationAdapter
private View view;
private Stage stage;
// your own variables
public MyApp(ApplicationBundle applicationBundle) {
view = applicationBundle.getView();
}
#Override
public void create () {
stage = new Stage();
// add some textfields
final TextField tf1 = new TextField("", skin);
final TextField tf2 = new TextField("", skin);
tf1.setWidth((float)view.getWidth() * 0.6f);
tf2.setWidth((float)view.getWidth() * 0.6f);
tf1.setHeight((float)view.getHeight() * 0.05f);
tf2.setHeight((float)view.getHeight() * 0.05f);
view.addListener(new SizeChangeListener() {
#Override
public void onSizeChange(float width, float height) {
Gdx.app.log("INFO", "Visible area: " + width + " " + height);
Gdx.app.log("INFO", "Stage area: " + stage.getWidth() + " " + stage.getHeight());
float keyboardHeight = getKeyboardHeight();
// MOVE THEM OUT OF THE WAY :)
tf1.addAction(Actions.moveTo(width / 2 - tf1.getWidth() / 2.0f, keyboardHeight + (6 * (height / 8)), 1, Interpolation.sineOut));
tf2.addAction(Actions.moveTo(width / 2 - tf2.getWidth() / 2.0f, keyboardHeight + (7 * (height / 8)), 1, Interpolation.sineOut));
// Gdx.gl20.
// tf.setPosition(width / 2 - (tf.getWidth() / 2.0f), 0);
}
});
}
Perhaps create a little keyboard heigt method like I did:
private float getKeyboardHeight() {
return stage.getHeight() - view.getHeight();
}
Try
Gdx.input.isPeripheralAvailable(Input.Peripheral.OnscreenKeyboard);
I just looked this up in the docs, don't know if it actually does the trick. But the
Gdx.input.setOnscreenKeyboardVisible(boolean visible);
method could be used as well (like this YOU define when the keyboard is visible and when not).