Get measure of relative layout android? - android

I have an empty RelativeLayout. I must get height and width of layout (set to match the parent). I have tried to search online but, to no avail. This is my code, can you help me? When I launch the application it crashes in the getCoordinate method. Sorry for my English.
public class MainActivity extends AppCompatActivity {
Random rand = new Random();
int[] coordinate = new int[2];
public void getCordinate(final RelativeLayout layout){
layout.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
// Ensure you call it only once :
layout.getViewTreeObserver().removeGlobalOnLayoutListener(this);
coordinate[0] = layout.getMeasuredWidth();// width must be declare as a field
coordinate[1] = layout.getMeasuredHeight();// height must be declare as a fiel
}
});
}
public void makeButton(RelativeLayout play_area){
int button_x = rand.nextInt(coordinate[0]);
int button_y = rand.nextInt(coordinate[1]);
Button bomb = new Button(this);
bomb.setX((float)button_x);
bomb.setY((float)button_y);
play_area.addView(bomb);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RelativeLayout play_area = (RelativeLayout) findViewById(R.id.play_area);
play_area.measure(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT);
getCordinate(play_area);
Log.d("Coordinate", "Xmax: " + coordinate[0] + " Ymax: " + coordinate[1]);
//makeButton(play_area);
}
}

you shouldn't call measure(). you could maybe just call .setLayoutParams(width, height) to set the view to match parent's width/height.
and simply calling .getMeasuredWidth() (or height) on the view should return their width/height values

Related

findViewById with reverse search does not work

I'm confused right now. I expect, that something, which works one way, also works reversed as well. But apparently not... I'm creating a view programmatically in my the class PlayerView. In the method player_table I'm assigning an onclick listener. And that works perfectly fine. However in the class PlayerLifePoints_Functions I have created the onclick method. The method itself works fine. The problem is the following: I'm assigning id's manually (to make my work in future process steps easier). Now I can read the id from an element, which was clicked. However if I want to find exactly this element by the ID (e.g. 400) it does return an error:
Error: java.lang.NullPointerException: Attempt to invoke virtual method 'android.view.Window$Callback android.view.Window.getCallback()' on a null object reference at ...PlayerLifePoints_Functions.onClick(PlayerLifePoints_Functions.java:21) -> The line with the log command
I have no idea why. I have also tried using getParent(), but that does not work either. Any ideas, where the problem could be?
Class PlayerView
public class PlayerView extends View {
private RelativeLayout relativeLayout;
private TableLayout tableLayout;
private int player_loop;
private int player_count;
public PlayerView(Context context, int player_count){
super(context);
setPlayer_count(player_count);
}
public ScrollView create_scrollView(){
ScrollView scrollView = new ScrollView(getContext());
ScrollView.LayoutParams scroll_params = new ScrollView.LayoutParams(
ScrollView.LayoutParams.MATCH_PARENT,
ScrollView.LayoutParams.MATCH_PARENT
);
scrollView.setLayoutParams(scroll_params);
scrollView.addView(create_relativeLayout());
return scrollView;
}
public HorizontalScrollView create_relativeLayout(){
HorizontalScrollView horizontalScrollView = new HorizontalScrollView(getContext());
relativeLayout = new RelativeLayout(getContext());
RelativeLayout.LayoutParams relativeParams = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.MATCH_PARENT,
RelativeLayout.LayoutParams.MATCH_PARENT
);
relativeLayout.setLayoutParams(relativeParams);
create_Player_Table_Layout();
horizontalScrollView.addView(relativeLayout);
return horizontalScrollView;
}
public void create_Player_Table_Layout(){
for(player_loop = 1; player_loop <= player_count; player_loop++){
relativeLayout.addView(player_table(getResources().getString(R.string.dummy_player_name) + player_loop, player_loop));
}
}
public TableLayout player_table(String playername, int playernumber){
tableLayout = new TableLayout(getContext());
tableLayout.setId(playernumber * 1000);
if (playernumber > 1) {
//TABLE PLACEMENT
RelativeLayout.LayoutParams tbl_params_New = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
tbl_params_New.addRule(RelativeLayout.RIGHT_OF, (playernumber - 1) * 1000);
tableLayout.setLayoutParams(tbl_params_New);
}
//Add Playername
TableRow row_playername = new TableRow(getContext());
TextView view_name = new TextView(getContext());
TableRow.LayoutParams view_name_params = new TableRow.LayoutParams();
view_name_params.setMargins(20,20,20,20);
view_name.setLayoutParams(view_name_params);
view_name.setGravity(Gravity.CENTER);
view_name.setText(playername);
view_name.setTextSize(20);
view_name.setId(playernumber * 100);
//OnClickListener
PlayerName_Functions listener_name = new PlayerName_Functions();
view_name.setOnClickListener(listener_name);
row_playername.addView(view_name);
tableLayout.addView(row_playername);
//Add Lifepoints
TableRow row_lifepoints = new TableRow(getContext());
TextView view_lifepoints = new TextView(getContext());
TableRow.LayoutParams view_lifepoints_params = new TableRow.LayoutParams();
view_lifepoints_params.setMargins(20, 0, 20, 20);
view_lifepoints.setText("40");
view_lifepoints.setTextSize(40);
view_lifepoints.setGravity(Gravity.CENTER);
view_lifepoints.setId(playernumber * 100 + 10);
view_lifepoints.setLayoutParams(view_lifepoints_params);
//OnClickListener
PlayerLifePoints_Functions listener_lifepoints = new PlayerLifePoints_Functions();
view_lifepoints.setOnClickListener(listener_lifepoints);
row_lifepoints.addView(view_lifepoints);
tableLayout.addView(row_lifepoints);
for(int opponent_loop = 1; opponent_loop <= player_count; opponent_loop++){
tableLayout.addView(commander_damage_from_player(player_loop, opponent_loop));
}
return tableLayout;
}
Class PlayerLifePoints (Containing the OnClick Function implemented in the class above)
public class PlayerLifePoints_Functions extends AppCompatActivity implements View.OnClickListener {
#Override
public void onClick(View v) {
TextView textView = (TextView) v;
String lp = textView.getText().toString();
int id = textView.getId();
int playernumber = Character.getNumericValue(String.valueOf(id).charAt(0));
Log.d("Test", "ID: " + findViewById(v.getId()).getId());
// Intent intent = new Intent(v.getContext(), Update_LifePoints.class);
// intent.putExtra( "Update Reason", "Test");
//// intent.putExtra("Player Name", playername);
// intent.putExtra("Lifepoints", lp);
//
// v.getContext().startActivity(intent);
}
Your class PlayerLifePoints_Functions cannot use findViewById because it does not have content. Usually activities are started with Intents and they inflate a layout by overriding the onCreate method.
If you just want to make it work, you can use:
v.getRootView().findViewById(v.getId()).getId());
In that case you do not need to extend from AppCompatActivity
Or better just get rid of the class:
view_lifepoints.setOnClickListener( View.OnClickListener {
#Override
public void onClick(View v) {
TextView textView = (TextView) v;
String lp = textView.getText().toString();
int id = textView.getId();
int playernumber = Character.getNumericValue(String.valueOf(id).charAt(0));
Log.d("Test", "ID: " + findViewById(v.getId()).getId());
}
);
In general:
I would recommend not putting your whole logic into a view, but more down into a lower layer. Having it in the activity would already be an improvement for prototyping. If your code grows, it may make sense to switch to MVP or MVVM.
Google has some great resources to get you started:
https://developer.android.com/guide/components/activities/intro-activities
https://developer.android.com/topic/libraries/architecture/

Runtime Error, by starting the Application [duplicate]

This question already has answers here:
How to set Id of dynamic created layout?
(10 answers)
Closed 5 years ago.
I have written a small app in Android Studio. If I start the app in the emulator, then I get an exception. The application simply stops.
The source code looks as follows:
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private int points, round, countdown;
private static final int FROG_ID = 212121;
private Random rnd = new Random();
private Handler handler = new Handler();
private Runnable runnable = new Runnable(){
#Override
public void run(){
countdown();
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//newGame();
showStartFragment();
}
private void newGame(){
points = 0;
round = 1;
initRound();
}
private void initRound(){
countdown = 10;
ViewGroup container = (ViewGroup) findViewById(R.id.container);
container.removeAllViews();
WimmelView wv = new WimmelView(this);
container.addView(wv, ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT);
wv.setImageCount(5*(10+round));
ImageView frog = new ImageView(this);
frog.setId(FROG_ID);
frog.setImageResource(R.drawable.frog1);
frog.setScaleType(ImageView.ScaleType.CENTER);
float scale = getResources().getDisplayMetrics().density;
FrameLayout.LayoutParams lp= new FrameLayout.LayoutParams(Math.round(64*scale),Math.round(61*scale));
lp.leftMargin = rnd.nextInt(container.getWidth()-64);
lp.topMargin = rnd.nextInt(container.getHeight()-61);
lp.gravity = Gravity.TOP + Gravity.START;
frog.setOnClickListener(this);
container.addView(frog, lp);
handler.postDelayed(runnable, 1000-round*50);
update();
}
private void fillTextView(int id, String text){
TextView tv = (TextView) findViewById(id);
tv.setText(text);
}
private void update(){
fillTextView(R.id.points, Integer.toString(points));
fillTextView(R.id.round, Integer.toString(round));
fillTextView(R.id.countdown,
Integer.toString(countdown*1000));
}
private void showStartFragment(){
ViewGroup container = (ViewGroup) findViewById(R.id.container);
container.removeAllViews();
container.addView(
getLayoutInflater().
inflate(R.layout.fragment_start, null));
container.findViewById(R.id.start).setOnClickListener(this);
}
private void showGameOverFragment(){
ViewGroup container = (ViewGroup) findViewById(R.id.container);
container.addView(
getLayoutInflater().
inflate(R.layout.fragment_gameover, null));
container.findViewById(play_again).setOnClickListener(this);
}
#Override
public void onClick(View view) {
if(view.getId()==R.id.start){
startGame();
}else if(view.getId()==R.id.play_again){
showStartFragment();
}else if(view.getId()==FROG_ID){
handler.removeCallbacks(runnable);
Toast.makeText(this,R.string.kissed, Toast.LENGTH_SHORT).show();
//showToast(R.string.kissed);
points += countdown*1000;
round++;
}
initRound();
}
private void startGame() {
newGame();
}
private void countdown(){
countdown--;
update();
if(countdown<=0){
//frog.setOnClickListener(null);
showGameOverFragment();
}else {
handler.postDelayed(runnable, 1000-round*50);
}
}
#Override
protected void onPause(){
super.onPause();
handler.removeCallbacks(runnable);
}
}
At the beginning I came so far that I could at least press on start, now I am not at all more in the application pure ...
I have tried to googlen what it could be, but I have not succeeded in doing so. I also get a error message at the point frog.setId (FROG_ID).
In addition, I have yet another class, which implements images
public class WimmelView extends View {
private Random rnd;
private long randomSeed = 1;
private int imageCount;
private Paint paint = new Paint();
private static final int[]
images = { R.drawable.frog2,
R.drawable.frog3,R.drawable.frog4,
R.drawable.frog5,R.drawable.frog6};
public void setImageCount(int imageCount){
this.imageCount = imageCount;
randomSeed = System.currentTimeMillis();
invalidate();
}
public WimmelView(Context context){
super(context);
paint.setAntiAlias(true);
}
#Override
protected void onDraw(Canvas canvas){
super.onDraw(canvas);
rnd = new Random(randomSeed);
for(int image:images){
Bitmap bitmap =
BitmapFactory.decodeResource(getResources(),image);
for(int i=0; i<imageCount/images.length; i++){
float left = (float) (rnd.nextFloat()
*(getWidth()-bitmap.getWidth()));
float top = (float) (rnd.nextFloat()
*(getWidth()-bitmap.getWidth()));
canvas.drawBitmap(bitmap,left,top,paint);
}
bitmap.recycle();
}
}
}
I hope someone sees the error and can help me ...
Your error is that the Content view is removing all children from the screen including the textviews of the score and points that you are trying to use. I just helped you move to fragments offline and ensured you were good to go. Goodluck.
You can use this,
<item name="frog_id" type="id"/>
This give you unique value.
You add this in your ids.xml. and change your code
...
frog.setId(R.id.frog_id);
...
else if(view.getId()==R.id.frog_id)
Try this
This is related to setting the view id. You can't set the id with the following:
private static final int FROG_ID = 212121;
...
frog.setId(FROG_ID);
You need to define an id in res/values/ids.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item name="your_view_id" type="id"/>
</resources>
But this will against the purpose of creating a dynamic view.
Instead, you can use View.generateViewId for the id instead. But please remember that this method only work from API version 17. Here the excerpt:
int generateViewId ()
Generate a value suitable for use in setId(int). This value will not
collide with ID values generated at build time by aapt for R.id.

How to get programmatically width and height of Relative - Linear layout in android?

I required runtime dimensions of Relative/Linear Layout.
activity_home.xml:
<RelativeLayout
android:id="#+id/rlParent"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</RelativeLayout>
HomeActivity.java:
private int width, height;
RelativeLayout rlParent = (RelativeLayout) findViewById(R.id.rlParent);
w = rlParent.getWidth();
h = rlParent.getHeight();
Log.i("Width-Height", width+"-"+height);
Please share your thoughts.
Try this
#Override
public void onWindowFocusChanged(boolean hasFocus) {
// TODO Auto-generated method stub
super.onWindowFocusChanged(hasFocus);
updateSizeInfo();
}
private void updateSizeInfo() {
RelativeLayout rlayout = (RelativeLayout) findViewById(R.id.rlayout);
w = rlayout.getWidth();
h = rlayout.getHeight();
Log.v("W-H", w+"-"+h);
}
Well I have implemented by this way:
LinearLayout linearLayout = (LinearLayout)findViewById(R.id.layout);
ViewTreeObserver viewTreeObserver = linearLayout.getViewTreeObserver();
viewTreeObserver.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
linearLayout.getViewTreeObserver().removeGlobalOnLayoutListener(this);
int width = linearLayout.getMeasuredWidth();
int height = linearLayout.getMeasuredHeight();
}
});
This example is for Linear layout, for Relative layout follow same process.
Hope this would help you.
You can attach a OnGlobalLayoutListener to ViewTreeObserver of the relative layout which will get called when the view is attached to the window and it's actual height is assigned to it.
final RelativeLayout rl_cards_details_card_area = (RelativeLayout) findViewById(R.id.rl_cards_details_card_area);
rl_cards_details_card_area.getViewTreeObserver()
.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
// TODO Auto-generated method stub
int w = rl_cards_details_card_area.getWidth();
int h = rl_cards_details_card_area.getHeight();
Log.v("W-H", w + "-" + h);
rl_cards_details_card_area.getViewTreeObserver()
.removeOnGlobalLayoutListener(this);
}
});
try like this:
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.RelativeLayout;
import android.widget.TextView;
public class AndroidResizeView extends Activity {
TextView textMyTextView;
Button myButton;
RelativeLayout rlayout;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.hightk);
rlayout = (RelativeLayout) findViewById(R.id.rlayout);
textMyTextView = (TextView) findViewById(R.id.textView1);
myButton = (Button) findViewById(R.id.button1);
myButton.setOnClickListener(new Button.OnClickListener() {
#Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
updateSizeInfo();
}
});
}
#Override
public void onWindowFocusChanged(boolean hasFocus) {
// TODO Auto-generated method stub
super.onWindowFocusChanged(hasFocus);
updateSizeInfo();
}
private void updateSizeInfo() {
textMyTextView.setText(String.valueOf("Width: "
+ rlayout.getWidth() + "height ::" + rlayout.getHeight()));
}
}
we may not get correct height and wight of a view or layout as soon the activity is just created since the layout is not inflated completly
so
1.either you can let a runnable method triggered after some secs which in turn call a function that gets the width and height properties.
2.we can use view tree obsever
l = (RelativeLayout)findviewbyid(R.id.rl_cards_details_card_area);
ViewTreeObserver observer = l.getViewTreeObserver();
observer.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
// TODO Auto-generated method stub
ActivityClassName.this.getProperties();
l.getViewTreeObserver().removeGlobalOnLayoutListener(
this);
}
});
void getProperties() {
int a= l.getHeight();
int b = l.getWidth();
Toast.makeText(getActivity,""+a+" "+b,1000).show();
}
For Kotlin: You can use AndroidX's doOnLayout extension function to get height or width of a layout
view.doOnLayout {
Timber.d("View's Height: ${view.height}")
}
Performs the given action when this view is laid out. If the view has
been laid out and it has not requested a layout, the action will be
performed straight away, otherwise the action will be performed after
the view is next laid out.
The action will only be invoked once on the next layout and then
removed. For more info

ImageView scale issues

I have an ImageView (original size: 500 x 80) . I am changing its width parameter like this:
imageView1.getLayoutParams().width=(int) (500.0*width_proc);
When I use ImageView.getWidth() the result is 555, which is perfect.
When I use ImageView.getHeight() the result is still 80. It doesn't update to the new value, even though the image is automatically rescaled.
I tried to add a Sleep(100), to use ImageView.getViewTreeObserver().addOnGlobalLayoutListener, or to add measure() functions, nothing works.
Code looks like this:
...
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
View myView=this.findViewById(android.R.id.content);
myView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
public void onGlobalLayout() {
BuildGraphInterface();
}
});
}
........
public void BuildGraphInterface()
{
.......
//================= search 1 ===========================//
ImageView imageView1 = (ImageView) findViewById(R.id.imageview1);
imageView1.getLayoutParams().width=(int) (500.0*width_proc);
imageView1.requestLayout();
imageView1.invalidate();
TextView textView1 = (TextView) findViewById(R.id.textview1);
textView1.setText( " " + imageView1.getHeight() + " " + imageView1.getWidth() );
.......
}

How can I know in my own view that device orientation has changed?

I extend ViewFlipper widget. When I initializ MyViewFlipper I pass List oа object to it. MyViewFlipper perform it list and add some views to MyViewFlipper.
My activity has android:configChanges="keyboardHidden|orientation", therefor my views hiererchy not recreating when device orientation changed.
Which method I must override in my MyViewFlipper to process orientation changed event to recreate my child views in MyViewFlipper?
How to do it others views?
Methid, that perform List of object in MyViewFlipper:
public void setUsers(List<User> users)
{
removeAllViews();
Display display = ((WindowManager)getContext().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
int maxWidth = display.getWidth();
screens = new LinearLayout[maxScreens];
int fillingScreen = maxScreens;
while(fillingScreen > 0)
{
LinearLayout linearLayout = new LinearLayout(getContext());
linearLayout.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.FILL_PARENT));
linearLayout.setGravity(Gravity.CENTER);
screens[fillingScreen - 1] = linearLayout;
fillingScreen --;
}
int currentUser = 0;
while(currentUser < users.size() && fillingScreen < maxScreens)
{
LinearLayout linearLayout = (LinearLayout) inflater.inflate(R.layout.item_people_category_item, null);
ImageView iv = (ImageView) linearLayout.findViewById(R.id.item_people_category_item_avatar);
screens[fillingScreen].addView(linearLayout);
screens[fillingScreen].measure(0, 0);
if (screens[fillingScreen].getMeasuredWidth() >= maxWidth)
{
screens[fillingScreen].removeView(linearLayout);
addView(screens[fillingScreen]);
fillingScreen ++;
}
else
{
User user = users.get(currentUser);
iv.setOnClickListener(ouUserClicked);
linearLayout.setTag(user);
App._IMAGEMANAGER.setImage(user.getPhoto(), iv, R.drawable.no_photo);
currentUser++;
}
}
if (fillingScreen < maxScreens && screens[fillingScreen].getParent() == null) addView(screens[fillingScreen]);
}
It simpe add some LinwarLayout to ViewFlipper with muximim possiable number of objects.
PS:
#Override
public void onConfigurationChange(Configuration newConf) {
// notify view flopper here
}
Other views in my layout not need to notify. They change representation self. Whih method they use for it? onMeauser()?
You should override
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}
this to detect orientation changes...
It is not the method of view, nut method of activity:
#Override
public void onConfigurationChange(Configuration newConf) {
// notify view flopper here
}

Categories

Resources