null pointer exception when referencing layout view - android

My variable hz is null, why is this?
code:
HorizontalScrollView hz = (HorizontalScrollView) findViewById((R.id.horizontalScrollView2));
hz.addView(imageView, params);
hz.setBackgroundColor(Color.BLACK);
// Show this layout in our activity.
ScrollView scrollView = (ScrollView) findViewById(R.id.scrollView);
setContentView(scrollView);
xml:
<ScrollView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/scrollView">
<HorizontalScrollView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/horizontalScrollView2">
<AbsoluteLayout
android:layout_width="1000dp"
android:layout_height="1000dp"
android:id="#+id/al"/>
</HorizontalScrollView>
</ScrollView>
Also it won't allow me to have my absoluteLayout within the horizontalScrollView. I'm trying to make a drawable area bigger than the screen size that you can scroll both up and down, where I will be drawing a board game board. Can someone give me a hand to get this drawable area set up? Thanks.
All code of my activity:
package com.example.btf.game;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Bundle;
import android.widget.HorizontalScrollView;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.ScrollView;
public class SplashScreen extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// We'll be creating an image that is 100 pixels wide and 200 pixels tall.
int width = 1000;
int height = 3000;
// Create a bitmap with the dimensions we defined above, and with a 16-bit pixel format. We'll
// get a little more in depth with pixel formats in a later post.
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
// Create a paint object for us to draw with, and set our drawing color to blue.
Paint paint = new Paint();
paint.setColor(Color.BLUE);
// Create a new canvas to draw on, and link it to the bitmap that we created above. Any drawing
// operations performed on the canvas will have an immediate effect on the pixel data of the
// bitmap.
Canvas canvas = new Canvas(bitmap);
// Fill the entire canvas with a red color.
canvas.drawColor(Color.RED);
// Draw a rectangle inside our image using the paint object we defined above. The rectangle's
// upper left corner will be at (25,50), and the lower left corner will be at (75,150). Since we set
// the paint object's color above, this rectangle will be blue.
canvas.drawRect(25, 50, 75, 150, paint);
// In order to display this image in our activity, we need to create a new ImageView that we
// can display.
ImageView imageView = new ImageView(this);
// Set this ImageView's bitmap to the one we have drawn to.
imageView.setImageBitmap(bitmap);
// Create a simple layout and add our image view to it.
RelativeLayout layout = new RelativeLayout(this);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT);
params.addRule(RelativeLayout.CENTER_IN_PARENT);
// LinearLayout container = (LinearLayout) findViewById(R.id.container);
HorizontalScrollView hz = (HorizontalScrollView) findViewById((R.id.horizontalScrollView2));
hz.addView(imageView, params);
hz.setBackgroundColor(Color.BLACK);
// Show this layout in our activity.
ScrollView scrollView = (ScrollView) findViewById(R.id.scrollView);
setContentView(scrollView);
}
}

Your views are null because there are not a part of activity at time you're trying to get them through findViewById() method.
You need to call setContentView() before "finding" views and pass your xml layout in it: setContentView(R.layout.my_acitivty_layout)

Related

How to programmatically add two images to button along with two lines of text?

I want to add two images to a button that has two lines of text, like so:
Note: the above image is photoshopped to look like what I want.
I am not sure how to achieve this. I can programmatically add one image to the button on the left like so:
Button button = new Button(this);
int imgResource = R.drawable.titans;
String matchUpStr = "Titans\nPatriots";
button.setGravity(Gravity.START);
button.setCompoundDrawablesWithIntrinsicBounds(imgResource, 0, 0, 0);
button.setText(matchUpStr);
but it just ends up like this:
Does anyone know how I could add the two images to the left of the text in the button? I am thinking maybe you can go to the next line on the imgResource variable and add another drawable. Not sure.
note that I will be dynamically creating buttons and it is not always going to be this matchup. So I can't just add an image with these two teams on it.
I'm starting to think that maybe instead of adding two images along with two lines of text, why not just make two images that contain the text inside the images and add the images top and bottom.
Although I agree with Nero that a custom button is probably a cleaner solution.
I was able to come up with a solution using a LayerListDrawable.
I resized both bitmap drawables to be the size of the button's text and then inset them by that size in the layer list drawable. See the code example.
package cj.com.testinglayerlist;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.graphics.drawable.ScaleDrawable;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = findViewById(R.id.button);
// We will need to know the size of the text in order to correctly resize our bitmaps. I
// am getting it from the button here, but it can also be retrieved from resources.
int buttonTextSize = (int) button.getTextSize();
// Get the drawables as BitmapDrawables.
BitmapDrawable patriotsDrawable = (BitmapDrawable) getDrawable(R.drawable.patriots);
BitmapDrawable titansDrawable = (BitmapDrawable) getDrawable(R.drawable.titans);
// Resize the drawables to be the size of our button text.
patriotsDrawable = resizeDrawable(buttonTextSize, patriotsDrawable);
titansDrawable = resizeDrawable(buttonTextSize, titansDrawable);
// Create an array of drawables that contains our two logos.
Drawable[] drawables = new Drawable[2];
drawables[0] = patriotsDrawable;
drawables[1] = titansDrawable;
// Create a layer drawable.
LayerDrawable layerDrawable = new LayerDrawable(drawables);
// Notice here how the top of this layer is the button text size. This is opposite of the
// other drawable whom's bottom will be the button text size.
layerDrawable.setLayerInset(0,0, buttonTextSize,0,0);
layerDrawable.setLayerInset(1,0, 0,0,buttonTextSize);
// Now I set my buttons drawable.
button.setCompoundDrawablesWithIntrinsicBounds(layerDrawable, null,null,null);
}
/**
* Takes in the desired size of the bitmap drawable and resizes the bitmap as such.
*
* #param sizeOfDrawable The desired size in pixels.
* #param bitmapDrawable The bitmap drawable to resize.
*
* #return Bitmap drawable that has been resized.
*/
private BitmapDrawable resizeDrawable(int sizeOfDrawable, BitmapDrawable bitmapDrawable) {
Bitmap bitmap = bitmapDrawable.getBitmap();
BitmapDrawable d = new BitmapDrawable(getResources(), Bitmap.createScaledBitmap(bitmap,
sizeOfDrawable,
sizeOfDrawable, true));
return d;
}
}
I was able to conjure the following using my above code snippet.
It is not 100%, but maybe a path that you can take to accomplish your goal.
Layer List Drawable Screenshot
The only solution that comes to mind is place a Button inside a relative layout (or any layout you prefer) match parent then organize the view over it (Just make sure that on api 21+ the button has elevation set it to 0 or something).
This link inspired me: Android Custom button with imageview and textview inside?

Drawing shapes programmatically for Android

I'm new to the Android SDK so I'm trying to figure this out. I have read the documentation and a text book and they haven't been particularly helpful in this matter.
I'm just trying to draw a simple rectangle in a linear layout on the screen. I can't get the shape to show up, however, when I add text to this layout in the same fashion, the text does show up. What am I missing?
package jorge.jorge.jorge;
import android.app.Activity;
import android.graphics.Color;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.RectShape;
import android.os.Bundle;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
public class ShapesActivity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ShapeDrawable rect = new ShapeDrawable(new RectShape());
rect.getPaint().setColor(Color.GREEN);
ImageView view1 = new ImageView(this);
view1.setImageDrawable(rect);
LinearLayout frame = (LinearLayout)findViewById(R.id.linear1);
frame.addView(view1);
// TextView tx = new TextView(this);
//
// tx.setText("Hello World");
//
// frame.addView(tx);
}
}
The Shape is usually used for making a background to some View. Its width and height is the same of the view that is using it. Then, if this view has no width and height, It'll have no width and height, too.
Basically, I think that your ImageView has no width and height, then it's invisible.
You can see how to set it programatically here:
Set ImageView width and height programmatically?
But, I recomend you to make the layout in XML's way.

Overlay image on top of button

Here is my unanswered question:
Add new item count to icon on button - Android
Basically I want to display "new" counts on top. I see it as overlaying some view over existing button. How this can be done?
Easiest thing to do is:
Use a RelativeLayout with layout_height and layout_width set to WRAP_CONTENT.
Put one Button into the RelativeLayout with layout_height and layout_width set to WRAP_CONTENT.
Add an ImageView into the RelativeLayout aligned to PARENT_TOP and PARENT_RIGHT and set the visibility to GONE.
Then you can simply set the ImageView's drawable to the appropriate count image and set the visibility to VISIBLE.
Ok here is what i'd do:
Create a custom control that extends button. I'm not going to do the pretty graphics for you but this will give you the basic idea:
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.widget.Button;
public class CounterButton extends Button{
protected int count=0;
protected final Paint myTextPaint = new Paint();
protected final Paint myCirclePaint = new Paint();
public CounterButton(Context context, AttributeSet attrs) {
super(context, attrs);
this.setBackgroundDrawable(getResources().getDrawable(android.R.drawable.ic_dialog_email));
this.myCirclePaint.setARGB(150, 255, 0, 0);
this.myTextPaint.setARGB(150, 255, 255, 255);
}
#Override
protected void onDraw(Canvas canvas) {
if(count!=0){
canvas.drawCircle((float) (this.getWidth()*.75), (float) (this.getHeight()*.4), this.getHeight()/5, myCirclePaint);
canvas.drawText(Integer.toString(count), (float) (this.getWidth()*.75), (float) (this.getHeight()*.4), this.myTextPaint);
}
}
}
Clean up the sizing of your text you draw, the circle positioning (and add a border etc) and you have a custom control. You could further extend it so you could set the background in xml or dynamically and you have a reusable control with a number counter in a circle.
then in your code you could do:
CounterButton cb=(CounterButton) findViewById(R.id.whateverYouGaveItInXML);
cb.count=SomeNewNumber;
cb.invalidate;
the invalidate will redraw the image with the new value in the circle.
I used a button in the event you want to have it clickable easily and all that - but you could just as easily extend view if you are just doing a view.

How do a create a landscape version of my view without actually being in landscape mode?

I am trying to make a view controller that is fixed in portrait mode, but that has a landscape version that can "fade in" over the top. What this means is that I need to be able to have a version of the screen that is the correct size for landscape, and is rotated 90 (or 270 depending) degrees. On iPhone this was easy, but I'm struggling with Android. I've got a custom view containing the view I want rotated, but I can't seem to size the child view correctly, or get the rotation to line up correctly. Is there an easier way? Alternatively, what am I doing wrong here?
#Override
protected void onDraw(Canvas canvas) {
if (getChildCount() == 1) {
canvas.save();
canvas.rotate(90, canvas.getWidth() / 2, canvas.getHeight() / 2);
// I have no idea what my pivot point should be
View child = getChildAt(0);
Bitmap bitmap = // bitmap of child
Paint paint = new Paint();
canvas.drawBitmap(bitmap, 0, 0, paint);
canvas.restore();
}
}
#Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
if (getChildCount() == 1) {
View child = getChildAt(0);
child.layout(top, left, bottom, right);
}
}
What is not helpful is suggesting actually changing the orientation of the view controller. I need it to stay in portrait mode in order to show the portrait version at the same time with a partial alpha transparency.
To be clear, I need to be able to interact with the view in its rotated coordinates, so I need to be able to press buttons, use a scrollview, etc.
API Level 11 introduces setRotationX/Y for Views, which seems to be exactly what you're looking for.
Supposing Honeycomb is not you target API version, here's what I found out after a few hours toying with this (definitely more challenging than my current project!):
Rendering is certainly doable (and relatively easy)
It's a massive hack and you shouldn't be doing it in the first place
Basically, the main issue is not rendering but processing events. Since Android has no idea that the view is sideways (you just rendered it that way), the view will respond to the area bounded by original pre-rotation coordinates. Therefore, no clicking (well, unless you have a square button that just has the text sideways!).
Really, you should probably look into backporting the Honeycomb changes.
With that said and with a large disclaimer that there might be a multitude of cases where this won't work, here's a sample app:
package com.side;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.os.Bundle;
import android.util.Log;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.RelativeLayout;
import android.widget.RelativeLayout.LayoutParams;
import android.widget.TextView;
public class TestActivity extends Activity {
private class SidewaysGroup extends ViewGroup{
public SidewaysGroup(Context context) {
super(context);
}
#Override
protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
Log.i("Sideways", "Parent size: " + getWidth() + "x" + getHeight() + ", child size: " + child.getWidth() + "x" + child.getHeight());
// Create a new canvas for the child (there's probably a way to use the original canvas but I couldn't figure out the transformations)
Canvas childCanvas = new Canvas();
Bitmap childBitmap = Bitmap.createBitmap(child.getWidth(), child.getHeight(), Bitmap.Config.ARGB_8888);
childCanvas.setBitmap(childBitmap);
boolean ret = super.drawChild(childCanvas, child, drawingTime);
Matrix matrix = new Matrix();
// rotate at the bottom left corner
matrix.postRotate(90f, 0, childBitmap.getHeight());
// after the rotation we are one `height` further down than we should be
matrix.postTranslate(0, -childBitmap.getHeight());
canvas.drawBitmap(childBitmap, matrix, new Paint());
return ret;
}
#Override
protected void onLayout(boolean changed, int left, int top, int right,
int bottom) {
if(changed && getChildCount()==1)
{
final View child = getChildAt(0);
// This is breaking the flow (measuring would be done twice) - should be moved to onMeasure or measure() itself
// notice that it inverts the dimensions
child.measure(MeasureSpec.makeMeasureSpec(getMeasuredHeight(),
MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(
getMeasuredWidth(), MeasureSpec.AT_MOST));
child.layout(0, 0, child.getMeasuredWidth(), child.getMeasuredHeight());
}
}
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TextView verticalView = new TextView(this);
verticalView.setText("This is the vertical text");
verticalView.setGravity(Gravity.CENTER);
verticalView.setTextSize(50f);
verticalView.setTextColor(Color.parseColor("#88ffffff")); // add a bit of transparency to the text
SidewaysGroup group = new SidewaysGroup(this);
Button horizontalButton= new Button(this);
horizontalButton.setText("This is the horizontal button");
horizontalButton.setGravity(Gravity.CENTER);
horizontalButton.setTextSize(50f);
horizontalButton.setBackgroundDrawable(null);
horizontalButton.setTextColor(Color.WHITE);
horizontalButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
Log.i("Sideways", "Button click");
}
});
group.addView(horizontalButton);
RelativeLayout mainLayout = new RelativeLayout(this);
RelativeLayout.LayoutParams relparams = new RelativeLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);
relparams.addRule(RelativeLayout.CENTER_IN_PARENT);
mainLayout.addView(verticalView, relparams);
mainLayout.addView(group, relparams);
setContentView(mainLayout);
mainLayout.requestLayout();
}
}
Focusing and translating events are left as an exercise to the reader :)
Do You want to scroll in both views (Vertical and Horizontal?)
If not, maybe you can take a screenshot of the vertical text (see here ) then do an actual rotation of your layout (i know you didn't want that but I don't understand why, if the vertical view is just needed as an overlay) and then use the screenshot of the vertical screen as an simple transparent bitmap overlay...
From your comments it sounds like you want this:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<LinearLayout
android:id="#+id/linearlayout1"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" />
</LinearLayout>
<LinearLayout
android:id="#+id/linearlayout2"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" />
</LinearLayout>
</FrameLayout>
but I can't see how or why you would want this

Android Views Are Not As Tall As Specified

I am using RelativeLayout to position views at precise locations on the screen. This works as expected when using a view that say, draws a rectangle. But when using Android views like EditText, they are drawn shorter than specified by about 8 units. Clicking outside of the drawn EditText (but within the parameters specified by RelativeLayout) will, in fact, hit the EditText.
Here is some code to illustrate what I mean:
package com.DrawDemo;
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.RelativeLayout;
public class DrawDemo extends Activity
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
RelativeLayout l = new RelativeLayout(this);
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(100,100);
lp.leftMargin = 50;
lp.topMargin = 50;
DemoView demoview = new DemoView(this);
l.addView(demoview, lp);
EditText editText = new EditText(this);
l.addView(editText, lp);
setContentView(l);
}
private class DemoView extends View
{
public DemoView(Context context)
{
super(context);
}
#Override protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.GREEN);
canvas.drawPaint(paint);
}
}
}
If you execute this, you will notice that the EditText is noticeably shorter than the rectangle. I've tried mucking with onMeasure, setMinimumXXX, and just about everything else I can think of. So far, the only thing that works with some level of success is to just add 8 or so pixels to the height (8 seems to work better than trying a percentage of the height).
Next task will be to step into the source but was wondering if somebody has already solved this.
Thanks.
It's just because of the actual EditText background image that's used. Buttons are the same way, for some reason Google decided to draw the 9-patch background images with some extra transparent padding pixels. Really, the only solution, if it's a problem, would be to draw your own 9-patch, or modify the existing Android 9-patch to remove the extra pixels.

Categories

Resources