Hi I've been having problems with my code with null pointer exceptions (see my other questions) so I've gone for creating my view dynamically.
Here's my code:
public class HarvestLifeActivity extends Activity implements OnTouchListener {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//add touch listeners for buttons : assign each a name and link it.
View MoveUp = findViewById(R.id.up);
MoveUp.setOnTouchListener(this); // use (this) to link to the current onTouchListener references in class declaration above.
View MoveDown = findViewById(R.id.down);
MoveDown.setOnTouchListener(this);
View MoveLeft = findViewById(R.id.left);
MoveLeft.setOnTouchListener(this);
View MoveRight = findViewById(R.id.right);
MoveRight.setOnTouchListener(this);
}
#Override
protected void onStart() {
super.onStart();
Drawable standing = getResources().getDrawable(R.drawable.test_circle);
//code to convert character size from pixel to dp
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
float logicalDensity = metrics.density;
int pxToConv = 50;
int convToDp = (int) (pxToConv / logicalDensity + 0.5);
RelativeLayout characterContainer = new RelativeLayout(this);
RelativeLayout.LayoutParams characParams = new RelativeLayout.LayoutParams(convToDp, convToDp);
characParams.addRule(RelativeLayout.CENTER_IN_PARENT);
characterContainer.setBackgroundDrawable(standing);
characterContainer.setId(101);
}
// Process button clicks
public boolean onTouch(View v, MotionEvent event) {
switch(v.getId()){
case R.id.up:
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
//as long as up button is pressed it will keep moving character up
while (event.getAction() == MotionEvent.ACTION_DOWN)
{
RelativeLayout characterContainer = (RelativeLayout) findViewById(101);
Drawable walking = getResources().getDrawable(R.drawable.test_circle_red);
int startX = characterContainer.getLeft();
int startY = characterContainer.getTop();
int defaultWidth = characterContainer.getWidth();
int defaultHeight = characterContainer.getHeight();
//create new position for character 1 pixel closer to the top of screen
int newX = startX - 1;
int newY = startY;
//remove character
RelativeLayout view = (RelativeLayout) characterContainer;
ViewGroup owner = (ViewGroup) view.getParent();
owner.removeView(view);
//re make character in new position created above and assign background as walking forwards animation
RelativeLayout.LayoutParams characParams = new RelativeLayout.LayoutParams(defaultWidth,defaultHeight);
characParams.leftMargin = newY;
characParams.topMargin = newX;
characterContainer.setLayoutParams(characParams);
characterContainer.setBackgroundDrawable(walking);
}
break;
// when button is let go of
case MotionEvent.ACTION_UP:
RelativeLayout characterContainer = (RelativeLayout) findViewById(101);
Drawable standing = getResources().getDrawable(R.drawable.test_circle);
characterContainer.setBackgroundDrawable(standing);
default:
break;
}
return true;
case R.id.down:
.. ..
}
return true;
}
}
When I run it the created layout is not there.
Is there something I've missed?
You are creating a RelativeLayout object, but never setting it as the content for the window...
make your onCreate Look like this:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Cut these lines out of onStart();
RelativeLayout characterContainer = new RelativeLayout(this);
RelativeLayout.LayoutParams characParams = new RelativeLayout.LayoutParams(convToDp, convToDp);
characParams.addRule(RelativeLayout.CENTER_IN_PARENT);
characterContainer.setBackgroundDrawable(standing);
characterContainer.setId(101);
setContentView(characterContainer);
//add touch listeners for buttons : assign each a name and link it.
/*View MoveUp = findViewById(R.id.up);
MoveUp.setOnTouchListener(this); // use (this) to link to the current onTouchListener references in class declaration above.
View MoveDown = findViewById(R.id.down);
MoveDown.setOnTouchListener(this);
View MoveLeft = findViewById(R.id.left);
MoveLeft.setOnTouchListener(this);
View MoveRight = findViewById(R.id.right);
MoveRight.setOnTouchListener(this);*/
}
you are not adding your created layout to the existing view.
thats your problem.
addview(your_layout);
Related
Finally found a workaround: I decided to just use a table with a single row and then set stretchAllColumns to true. This means it just mimics a horizontal layout with spread-out views.
I am trying to instantiate a horizontal linear layout at runtime and I would like the elements in the layout to spread out along the full width of the layout. I would also like everything to be center-vertical aligned. This is currently what I've got:
LinearLayout tertiaryLinearLayout = new LinearLayout(getActivity());
tertiaryLinearLayout.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
tertiaryLinearLayout.setOrientation(LinearLayout.HORIZONTAL);
tertiaryLinearLayout.setGravity(Gravity.FILL_HORIZONTAL);
This instantiates the layout but the elements in it don't correctly fill the full width of it. I am also not sure how I can get them to be center-vertical aligned without changing setGravity to
tertiaryLinearLayout.setGravity(Gravity.CENTER_VERTICAL);
This TextView is one of the five elements I add to the layout:
TextView dash = new TextView(getActivity());
dash.setText("-");
Two of the elements are ImageViews and the other three are TextViews. Here is how it looks currently:
https://i.stack.imgur.com/MGLyJ.jpg
EDIT:
The overall structure is a ScollView with a vertical LinearLayout. This LinearLayout holds lots of other vertical LinearLayouts, each with a horizontal LinearLayout. Hope that makes sense.
The parent view of tertiaryLinearLayout is here:
LinearLayout secondaryLinearLayout = new LinearLayout(getActivity());
secondaryLinearLayout.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT));
secondaryLinearLayout.setOrientation(LinearLayout.VERTICAL);
...
secondaryLinearLayout.addView(tertiaryLinearLayout);
EDIT 2:
Here is my full code:
...
final LinearLayout linearLayout = root.findViewById(R.id.leagueLinearLayout);
List<Game> currentYearCategory = MainActivity.yearCategories.get(0);
for (int i = 0; i < currentYearCategory.size(); i++) {
TextView textView = new TextView(getActivity());
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT);
textView.setLayoutParams(params);
textView.setText(currentYearCategory.get(i).date);
linearLayout.addView(textView);
}
seekBarChange(linearLayout, root, 0);
// Set up seek bar
SeekBar yearSeekBar = root.findViewById(R.id.yearSeekBar);
yearSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
#Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
seekBarChange(linearLayout, root, progress);
}
...
...
private void seekBarChange(LinearLayout linearLayout, View root, int progress){
TextView yearTextView = root.findViewById(R.id.yearTextView);
String newText = (1890 + progress * 10) + " - " + (1899 + progress * 10);
yearTextView.setText(newText);
final List<Game> currentYearCategory = MainActivity.yearCategories.get(progress);
linearLayout.removeAllViews();
for (int i = 0; i < currentYearCategory.size(); i++) {
// Create views
LinearLayout secondaryLinearLayout = new LinearLayout(getActivity());
secondaryLinearLayout.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT));
secondaryLinearLayout.setOrientation(LinearLayout.VERTICAL);
View separatorView = new View(getActivity());
separatorView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 50));
TextView date = new TextView(getActivity());
date.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
date.setText(currentYearCategory.get(i).date);
LinearLayout tertiaryLinearLayout = new LinearLayout(getActivity());
tertiaryLinearLayout.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT));
tertiaryLinearLayout.setOrientation(LinearLayout.HORIZONTAL);
tertiaryLinearLayout.setGravity(Gravity.CENTER_VERTICAL);
ImageView homeImage = new ImageView(getActivity());
homeImage.setLayoutParams(new ViewGroup.LayoutParams(150, 150));
if (currentYearCategory.get(i).celticIsHome){
homeImage.setBackgroundResource(R.drawable.celtic_logo);
} else {
homeImage.setBackgroundResource(R.drawable.rangers_logo);
}
TextView homeScore = new TextView(getActivity());
homeScore.setText(currentYearCategory.get(i).fullTimeScore.substring(0, 1));
TextView dash = new TextView(getActivity());
dash.setText("-");
TextView awayScore = new TextView(getActivity());
awayScore.setText(currentYearCategory.get(i).fullTimeScore.substring(2));
ImageView awayImage = new ImageView(getActivity());
awayImage.setLayoutParams(new ViewGroup.LayoutParams(150, 150));
if (currentYearCategory.get(i).celticIsHome){
awayImage.setBackgroundResource(R.drawable.rangers_logo);
} else {
awayImage.setBackgroundResource(R.drawable.celtic_logo);
}
// Add views
tertiaryLinearLayout.addView(homeImage);
tertiaryLinearLayout.addView(homeScore);
tertiaryLinearLayout.addView(dash);
tertiaryLinearLayout.addView(awayScore);
tertiaryLinearLayout.addView(awayImage);
secondaryLinearLayout.addView(separatorView);
secondaryLinearLayout.addView(date);
secondaryLinearLayout.addView(tertiaryLinearLayout);
final int gameNum = i;
secondaryLinearLayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
openGameActivity(currentYearCategory, gameNum);
}
});
linearLayout.addView(secondaryLinearLayout);
}
}
Any help would be greatly appreciated, thanks!
I guess that the PARENT view that the tertiaryLinearLayout will be added to is wrap_content for the layout_width. Try to make its width match_parent. You should have a look on this tutorial at 2:52s
I am trying to clean my java code by placing RelativeLayout.LayoutParams inside a function, so that I don't have to create new layoutparams everytime I add new thing.
The problem: I got an error code
Unable to start activity ComponentInfo{onedevz.com.noct/onedevz.com.noct.MainActivity}: java.lang.NullPointerException: Layout parameters cannot be null
it says I got no layout param even though I do have one and I called it before I placed it into a Button. here is the code
public class MainActivity extends AppCompatActivity {
MicButton micbutton;
Button menuBtn,onBtn;
EditText text;
RelativeLayout relativeLayout;
RelativeLayout.LayoutParams lp1,lp2,lp3,lp4;
boolean clicked;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Creating a new RelativeLayout
relativeLayout = new RelativeLayout(this);
// Defining the RelativeLayout layout parameters.
// In this case I want to fill its parent
RelativeLayout.LayoutParams rlp = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.FILL_PARENT,
RelativeLayout.LayoutParams.FILL_PARENT);
// Defining the layout parameters of the TextView
placement(lp1,100,100,0,200,40,0,RelativeLayout.ALIGN_PARENT_BOTTOM,RelativeLayout.ALIGN_PARENT_LEFT);
placement(lp2,100,100,0,350,40,0,RelativeLayout.ALIGN_PARENT_BOTTOM,RelativeLayout.ALIGN_PARENT_LEFT);
placement(lp3,100,100,0,500,40,0,RelativeLayout.ALIGN_PARENT_BOTTOM,RelativeLayout.ALIGN_PARENT_LEFT);
placement(lp4,100,ViewGroup.MarginLayoutParams.MATCH_PARENT,150,0,40,0,RelativeLayout.ALIGN_PARENT_TOP,RelativeLayout.CENTER_HORIZONTAL);
setParameter();
addView();
// Setting the RelativeLayout as our content view
setContentView(relativeLayout, rlp);
}
void placement(RelativeLayout.LayoutParams name,int height,int width,int topMargin,int bottomMargin,int leftMargin,int rightMargin,int rule1,int rule2){
name = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT);
name.addRule(rule1);
name.addRule(rule2);
name.leftMargin = leftMargin;
name.bottomMargin = bottomMargin;
name.height = height;
name.width = width;
}
void setParameter(){
// Setting the parameters on the TextView
micbutton.setLayoutParams(lp1);
onBtn.setLayoutParams(lp2);
menuBtn.setLayoutParams(lp3);
text.setLayoutParams(lp4);
}
void addView(){
// Adding the TextView to the RelativeLayout as a child
relativeLayout.addView(micbutton);
relativeLayout.addView(text);
}
}
Any help will be appreciated, Thanks.
Your LayoutParameters lp1,lp2,lp3,lp4 have not been initialized. Initialize them and then set it to the TextView.
Solution:
Write like this:
void placement(RelativeLayout.LayoutParams name,int height,int width,int topMargin,int bottomMargin,int leftMargin,int rightMargin,int rule1,int rule2){
name = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT);
name.addRule(rule1);
name.addRule(rule2);
name.leftMargin = leftMargin;
name.bottomMargin = bottomMargin;
name.height = height;
name.width = width;
void setParameter();
}
void setParameter(){
// Setting the parameters on the TextView
micbutton.setLayoutParams(lp1);
onBtn.setLayoutParams(lp2);
menuBtn.setLayoutParams(lp3);
text.setLayoutParams(lp4);
void addView();
}
void addView(){
// Adding the TextView to the RelativeLayout as a child
relativeLayout.addView(micbutton);
relativeLayout.addView(text);
}
Hopefully it should solve your issue.
In Android, I create an ImageView in the Java code and set its layout parameters: width, height and top margin before adding it to the main layout (RelativeLayout). The width and height are applied successfully, but the margin doesn't have any affect on the image view position. The actual top margin stays 0.
How to apply the top margin to views? The code is below.
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initClouds();
}
private void initClouds() {
addCloud(R.drawable.cloud1, R.dimen.cloud1_top_margin);
addCloud(R.drawable.cloud2, R.dimen.cloud2_top_margin);
}
private void addCloud(int imageResId, int topMarginResId) {
RelativeLayout mainLayout = (RelativeLayout) findViewById(R.id.mainLayout);
ImageView cloud = new ImageView(this);
int height = (int) getResources().getDimension(R.dimen.cloud_height);
int width = (int) getResources().getDimension(R.dimen.cloud_width);
ViewGroup.MarginLayoutParams params = new ViewGroup.MarginLayoutParams(width, height);
params.topMargin = (int) getResources().getDimension(topMarginResId);
cloud.setImageResource(imageResId);
mainLayout.addView(cloud, params);
}
}
For setting the margin for a view inside RelativeLayout you should use RelativeLayout.LayoutParams . Change your code like this ,
private void addCloud(int imageResId, int topMarginResId) {
RelativeLayout mainLayout = (RelativeLayout) findViewById(R.id.mainLayout);
ImageView cloud = new ImageView(this);
int height = (int) getResources().getDimension(R.dimen.cloud_height);
int width = (int) getResources().getDimension(R.dimen.cloud_width);
RelativeLayout.LayoutParams param = new RelativeLayout.LayoutParams(width, height);
param.topMargin = (int) getResources().getDimension(topMarginResId);
cloud.setImageResource(imageResId);
mainLayout.addView(cloud, param);
}
This seems to be easy to state but there seems no straight forward implementation. I want to limit the movement of an imageview to its direct parent. I couldn't find examples related to this. Can somebody help me with an example for this?
I actually want to achieve a motion where the leaf in middle is moved, the leaf at the top should move to bottom and the bottom leaf should move to the middle and the middle leaf should move to top position. This coupled with the elevation of the middle leaf. Please refer to the image below.
I have tried to achieve this by using the rect of the parent view in onTouch of the view but that doesn't seem to work. Tried to achieve this listview and recyclerview but that seems to add a lot of complexity to a simple requirement.
Here is my code
public class Main6Activity extends AppCompatActivity {
ImageView imageView;
private int _xDelta;
private int _yDelta;
View view;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main6);
imageView = (ImageView)findViewById(R.id.img1);
view = findViewById(R.id.imglayout);
final Rect rect = new Rect(view.getLeft(),view.getTop(),view.getRight(),view.getBottom());
imageView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
final int X = (int) event.getRawX();
final int Y = (int) event.getRawY();
if(event.getAction() == MotionEvent.ACTION_DOWN){
LinearLayout.LayoutParams lParams = (LinearLayout.LayoutParams) imageView.getLayoutParams();
_xDelta = X - lParams.leftMargin;
_yDelta = Y - lParams.topMargin;
}
if (event.getAction() == MotionEvent.ACTION_MOVE){
if(isViewContains(X,Y)){
LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) imageView.getLayoutParams();
layoutParams.leftMargin = X - _xDelta;
layoutParams.topMargin = Y - _yDelta;
layoutParams.rightMargin = -250;
layoutParams.bottomMargin = -250;
imageView.setLayoutParams(layoutParams);
}
}
return true;
}
});
}
private boolean isViewContains(int rx,int ry) {
int[] l = new int[2];
view.getLocationOnScreen(l);
Rect rect1 = new Rect(l[0], l[1], l[0] + view.getWidth(), l[1] + imageView.getHeight());
return rect1.contains(rx, ry);
}
}
I am trying to make a grid of image views, that when i drag another view over them(this view essentially acts as a mouse pointer), it changes the image I drag over in the grid to a different image. When I drag the "mouse" view away it will go back to normal.
Right now I have my mouse cursor view moving and have a grid of image views implemented with a grid view using a custom adaptor ( pictured below)
I can drag my cursor around but when ever I try to drag inside the gridview, it calls the image on the gridview's ontouch listener(only when i click on the image view, not when I slide over it). I also cannot seem to get onHover working on the images in the image View.
Also, if the mouse view is covering one of the grid images, the ontouchlistener of the image view the grid is not called.
What is the best way( types of views, etc) to use to go about implementing this?
Here is some relevant code from what I have so far.
This is where I set up my grid view in my activity
GridView gridView;
gridView = (GridView) findViewById(R.id.gridView);
gridView.setAdapter(new ImageAdapter(this,new String [25]));
gridView.setOnDragListener(new MyDragListener());
gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View v,
int position, long id) {
}
});
gridView.setClickable(false);
This is the getView function in my adapter
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View gridView;
if (convertView == null) {
gridView = inflater.inflate(R.layout.vibe_pad_section, null);
final ImageView imageView = (ImageView) gridView
.findViewById(R.id.grid_item_image);
imageView.setImageResource(R.drawable.vibepadcircle);
imageView.setPadding(10,10,10,10);
imageView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent e) {
Log.e("here","here");
switch (e.getAction()) {
case MotionEvent.ACTION_MOVE:
Log.e("here2","here2");
}
imageView.setImageResource(R.drawable.bar_high);
return true;
}
});
VibePad.padTargets.add(imageView);
} else {
gridView = (View) convertView;
}
return gridView;
}
class MyDragListener implements View.OnDragListener {
#Override
public boolean onDrag(View v, DragEvent event) {
final int action = event.getAction();
ClipData dragData;
View p = (View) v.getParent();
Object index = p.getTag();
final int which = Integer.parseInt(index.toString());
boolean handled = true;
Log.e(" in on drag","in on drag") ;
switch (action) {
case DragEvent.ACTION_DRAG_EXITED:
// Report the drop/no-drop result to the user
((ImageView) v).setImageResource(R.drawable.bar_high);
break;
case DragEvent.ACTION_DRAG_ENTERED:
// just drop it
((ImageView) v).setImageResource(R.drawable.vibepadcircle);
break;
default :
break;
}
return handled;
}
You need to create a class that extends OnDragListener:
When ACTION_DRAG_ENTERED occurs, you can change the underlying image to something else. When you exist (you've dragged the view outside the bounding box of the the image on your gridview) then you can change it back to it's original image
class MyDragListener implements OnDragListener {
#Override
public boolean onDrag(View v, DragEvent event) {
final int action = event.getAction();
ClipData dragData;
View p = (View) v.getParent();
Object index = p.getTag();
final int which = Integer.parseInt(index.toString());
boolean handled = true;
switch (action) {
case DragEvent.ACTION_DRAG_STARTED:
dragSku = event.getClipDescription().getLabel().toString();
break;
case DragEvent.ACTION_DRAG_ENDED:
// Report the drop/no-drop result to the user
final boolean dropped = event.getResult();
compareInMotion = false;
BaseAdapter lva = (BaseAdapter) gridview.getAdapter();
lva.notifyDataSetChanged();
break;
case DragEvent.ACTION_DROP:
// just drop it
((ImageView) v).setImageBitmap(emptyImg);
setUpCompareItem((ImageView) v, dragSku); break;
default :
break;
}
return handled;