Why is the SurfaceView cut if I resume app? - java

If I use an Android L device and resume my app, the SurfaceViews are cut.
The details of occurrence condition are as follows:
- Using Android L (It is originally L, not updated to L)
- The SurfaceView is larger than the display.
- The left-top of SurfaceView is more to the left or top of the display.
- Resuming the app from the background apps list, not the icon in the app list.
I tried to reset size, gravity, clip bounds, etc., however, none had effect.
I want to repair the SurfaceView cut, you do not have some idea?
The sample code is as follows:
[Activity]
public class ViewTestActivity extends Activity {
private DrawSurfaceView mDrawSurfaceView;
private int overDispW;
private int overDispH;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
WindowManager wm = (WindowManager) this.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
Point dispP = new Point();
display.getSize(dispP);
overDispW = (int) (dispP.x * 1.5);
overDispH = (int) (dispP.y * 1.5);
FrameLayout.LayoutParams overSizeParams = new FrameLayout.LayoutParams(overDispW, overDispH);
//If gravity is Gravity.LEFT|Gravity.TOP, there is no cut.
overSizeParams.gravity = Gravity.CENTER;
mDrawSurfaceView = new DrawSurfaceView(this);
setContentView(mDrawSurfaceView, overSizeParams);
}
}
[SurfaceView]
public class DrawSurfaceView extends SurfaceView implements SurfaceHolder.Callback{
private Paint mPaintRed;
private Paint mPaintBlue;
private Paint mPaintGreen;
private Paint mPaintYellow;
private SurfaceHolder mHolder;
public DrawSurfaceView(Context context) {
super(context);
mPaintRed = new Paint();
mPaintRed.setColor(Color.argb(255, 255, 0, 0));
mPaintBlue = new Paint();
mPaintBlue.setColor(Color.argb(255, 0, 0, 255));
mPaintGreen = new Paint();
mPaintGreen.setColor(Color.argb(255, 0, 255, 0));
mPaintYellow = new Paint();
mPaintYellow.setColor(Color.argb(255, 255, 255, 0));
mHolder = getHolder();
mHolder.setFormat(PixelFormat.RGBA_8888);
mHolder.addCallback(this);
}
public void onDraw(Canvas canvas){
super.onDraw(canvas);
drawRect(canvas);
}
private void drawRect(Canvas canvas) {
int w = canvas.getWidth();
int h = canvas.getHeight();
canvas.drawColor(Color.TRANSPARENT, Mode.CLEAR);
canvas.drawRect(0, 0, w/2, h/2, mPaintRed);
canvas.drawRect(w/2, h/2, w, h, mPaintBlue);
canvas.drawRect(w/2, 0, w, h/2, mPaintGreen);
canvas.drawRect(0, h/2, w/2, h, mPaintYellow);
}
public void doDraw(){
Canvas canvas = mHolder.lockCanvas();
if(canvas != null){
drawRect(canvas);
mHolder.unlockCanvasAndPost(canvas);
}
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
doDraw();
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
doDraw();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
}

Right side of view has been cut.

Related

Trying to populate the screen with objects

it seems I have a problem understanding classes. It would be great if someone could help.
I'm trying to populate my Smartphone screen (android) with 3 circles of different color.
My problem is that by using the code below I only get one (blue) circle.
I considered that the Problem is that the y-value isn't set correctly and the 3 circles are hiding each other (so that only the blue one is visible). But when I log the y-value of the 3 circle objects, the y-values seem to be correct (200,500,800)
Whats am I doing wrong?
Thanks for your help in advance.
public class MainActivity extends Activity {
public Circle circleR;
public Circle circleG;
public Circle circleB;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
circleR = new Circle(this, 200, 255, 0, 0);
setContentView(circleR);
circleG = new Circle(this, 500, 0, 255, 0);
setContentView(circleG);
circleB = new Circle(this, 800, 0, 0, 255);
setContentView(circleB);
}
}
public class Circle extends View {
public Paint paint;
public int y;
public Circle(Context context,int y, int r, int g, int b){
super(context);
paint=new Paint();
paint.setColor(Color.rgb(r,g,b));
this.y=y;
}
#Override
protected void onDraw(Canvas canvas){
canvas.drawCircle(30, this.y,30, paint);
}
}
The problem lies in setting the content view multiple times. Only the view set as last (the one with a blue circle) will be visible. If you want multiple circles to be visible at the same time you should draw them on one canvas localized inside one view. I rearranged your code so that it does what you wanted:
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
CirclesView circlesView = new CirclesView(this);
setContentView(circlesView);
}
}
public class CirclesView extends View {
public Circle circleR;
public Circle circleG;
public Circle circleB;
public CirclesView(Context context) {
super(context);
circleR = new Circle(200, 255, 0, 0);
circleG = new Circle(500, 0, 255, 0);
circleB = new Circle(800, 0, 0, 255);
}
#Override
protected void onDraw(Canvas canvas){
circleR.draw(canvas);
circleG.draw(canvas);
circleB.draw(canvas);
}
}
public class Circle {
public Paint paint;
public int y;
public Circle(int y, int r, int g, int b) {
paint = new Paint();
paint.setColor(Color.rgb(r,g,b));
this.y=y;
}
public void draw(Canvas canvas) {
canvas.drawCircle(30, this.y,30, paint);
}
}
Circle knows how to draw itself on a canvas which will be provided to it by a view.

Android PathShape not drawing path (Canvas/Java/Android Studio)

I'm just trying to draw a basic triangle in Android Studio but nothing is showing up when I run the program. This is my first Android program so I don't really know what I'm doing. What is wrong with it?
public class CustomDrawableView extends View {
private ShapeDrawable mDrawable;
public CustomDrawableView(Context context, Display display) {
super(context);
Point size = new Point();
display.getSize(size);
int screenWidth = size.x;
int screenHeight = size.y;
int pathWidth = screenWidth / 6;
int startWidth = screenWidth / 10;
Path path = new Path();
path.moveTo(startWidth, 0);
path.moveTo(startWidth, screenHeight / 5);
path.moveTo(screenWidth / 5, screenHeight / 5);
path.close();
mDrawable = new ShapeDrawable(new PathShape(path, screenWidth, screenHeight));
mDrawable.setDither(true);
int color = Color.parseColor("#ff74AC23");
mDrawable.getPaint().setColor(color);
mDrawable.setBounds(0, 0 , screenWidth, screenHeight);
}
protected void onDraw(Canvas canvas) {
mDrawable.draw(canvas);
}
}
public class MainActivity extends AppCompatActivity {
CustomDrawableView mCustomDrawableView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Display display = getWindowManager().getDefaultDisplay();
mCustomDrawableView = new CustomDrawableView(this, display);
setContentView(mCustomDrawableView);
}
}

Cannot use context in class?

I'm currently trying to put in a color from my colors resources xml into my app using ContextCompact.getColor() but for some reason I cannot pass in a single version of context.
I'm using a class as a handler so I am not trying to pass in from an activity. In my activity I can use them, but in my class I cannot pass in getActivityContext() this etc. Nothing works. What do I do?
Also, I'm adding the color to a canvas so I cannot add the color in in an xml.
canvas.drawColor(Color.BLACK);
Is what I'm currently forced to use. I want to replace it with a color from my xml. ( I'm trying to set the background of the canvas essentially )
full code of my class: (I'm making this app as a "note" app so that I can look back on it for future projects, hence all the comments)
public class GameHandling {
private SurfaceHolder holder;
private Resources resources;
private int screenWidth;
private int screenHeight;
private Ball ball;
private Bat player;
private Bat opponent;
public GameHandling(int width, int height, SurfaceHolder holder, Resources resources){
this.holder = holder;
this.resources = resources;
this.screenWidth = width;
this.screenHeight = height;
this.ball = new Ball(screenWidth, screenHeight, 400, 400);
this.player = new Bat(screenWidth, screenHeight, 0, 0, Bat.Position.LEFT);
this.opponent = new Bat(screenWidth, screenHeight, 0, 0, Bat.Position.RIGHT);
}
// setting the ball images to be drawn
public void inIt(){
Bitmap ballShadow = BitmapFactory.decodeResource(resources, R.mipmap.grey_dot);
Bitmap ballImage = BitmapFactory.decodeResource(resources, R.mipmap.red_dot);
Bitmap batPlayer = BitmapFactory.decodeResource(resources, R.mipmap.bat_player);
Bitmap batOpponent = BitmapFactory.decodeResource(resources, R.mipmap.bat_opponent);
ball.inIt(ballImage, ballShadow, 2, 0);
player.inIt(batPlayer, batPlayer, 0, 0);
opponent.inIt(batOpponent, batOpponent, 0, 0);
}
// calling Balls update method to update the ball
public void update(long elapsed){
ball.update(elapsed);
}
public void draw(){
Canvas canvas = holder.lockCanvas(); // Making a canvas object to draw on - .lockcanvas locks canvas
if(canvas != null) {
// draw in area between locking and unlocking
canvas.drawColor(Color.BLACK);
ball.draw(canvas);
player.draw(canvas);
opponent.draw(canvas);
holder.unlockCanvasAndPost(canvas); //-unlockcanvasandposts unlocks the canvas
}
}
}
Change your constructor to this and use ContextCompat.getColor(context,... pattern.
Wherever you are creating this class (activity/fragment), pass the context calling either getActivity() or getApplicationContext()
new GameHandling( getActivity()/getApplicationContext(), ...)
public GameHandling(Context context, int width, int height, SurfaceHolder holder, Resources resources){
this.context = context;
this.holder = holder;
this.resources = resources;
this.screenWidth = width;
this.screenHeight = height;
this.ball = new Ball(screenWidth, screenHeight, 400, 400);
this.player = new Bat(screenWidth, screenHeight, 0, 0, Bat.Position.LEFT);
this.opponent = new Bat(screenWidth, screenHeight, 0, 0, Bat.Position.RIGHT);
}
I kind of came up with a workaround, I created an image with my desirable color and then used that as the background of the app.
However it is still a workaround, so it doesn't solve my issue

Android View member variable becoming null

I have a custom android View that draws a waveform on the screen.
A variable, cursorTask is a TimerTask that somehow becomes null in between startCursor finishing execution and stopCursor being called. I don't see how this can be happening as it is private and all of the WaveView's startCursor functions are called.
public class WaveView extends View {
private Audio audio;
Paint wavePaint;
Paint progressPaint;
Paint barPaint;
private int progress;
private int maxProgress = 100;
private Timer timer;
private TimerTask cursorTask;
public WaveView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init(){
timer = new Timer();
wavePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
wavePaint.setColor(Color.BLUE);
wavePaint.setStyle(Paint.Style.FILL);
progressPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
progressPaint.setColor(Color.RED);
progressPaint.setStrokeWidth(2.0f);
barPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
barPaint.setColor(Color.CYAN);
barPaint.setAlpha(100);
}
public void setAudio(Audio audio){
this.audio = audio;
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if(audio != null && audio.waveValues != null && !audio.waveValues.isEmpty()){
int w = canvas.getWidth();
int h = canvas.getHeight();
canvas.drawRect(new Rect(0, 0, w*audio.bars/Rhythm.maxBars, h), barPaint);
Path path = new Path();
path.moveTo(0,h);
for(int i = 0; i < 100; i++){
int x = i * w/100;
if(audio.waveValues.size() <= i){
path.lineTo(x, h);
break;
}
int y = Math.round(h-audio.waveValues.get(i)*h);
path.lineTo(x, y);
}
path.lineTo(w,h);
canvas.drawPath(path, wavePaint);
if(0 < progress){
float x = progress*w*audio.bars/maxProgress/Rhythm.maxBars;
canvas.drawLine(x, h, x, 0, progressPaint);
}
}
}
public void startCursor(int msLoopDuration){
progress = 0;
cursorTask = new TimerTask() {
#Override
public void run() {
progress = (progress+1) % maxProgress;
postInvalidate();
}
};
timer.scheduleAtFixedRate(cursorTask, 0, msLoopDuration/maxProgress);
}
public void stopCursor(){
cursorTask.cancel();
}
}
I call it by finding the WaveView in the convertView in getView() in the adapter where the WaveView is.
WaveView wave = (WaveView)convertView.findViewById(R.id.waveform);
wave.startCursor(Rhythm.msBarPeriod()*audio.bars);
Any help would be greatly appreciated.

Android custom view not showing

I am working on an Android version of Gomoku. I am quite new to Java in general and even more so to Android. I am following a book called "Hello Android" where the author teaches the basics through making a game of Sudoku. I am following it loosely, leaving out features not needed for my Gomoku. However, a new view is made when New Game is pressed and although the book continues on as if it should be working, what should be drawn is not showing for me at all. Here is the code that deals with the stuff:
Mainactivity.java:
private void startGame() {
Log.d(TAG, "Clicked New Game");
Intent intent = new Intent(this, Game.class);
startActivity(intent);
}
Game.java:
public class Game extends Activity {
private static final String TAG = "Game";
private int board[] = new int[10 * 10];
private GameView gameView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "Game.onCreate called");
gameView = new GameView(this);
gameView.requestFocus();
Log.d(TAG, "Game.onCreate finished");
}
}
GameView.java:
public class GameView extends View {
private static final String TAG = "Game";
private float width; //Width of one tile
private float height; //Height of one tile
private final Game game;
Paint background = new Paint();
Paint dark = new Paint();
Paint light = new Paint();
Paint hilite = new Paint();
public GameView(Context context) {
super(context);
this.game = (Game) context;
setFocusable(true);
setFocusableInTouchMode(true);
Log.d(TAG, "GameView finished");
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
width = w / 10f;
height = h /10f;
Log.d(TAG, "onSizeChanged: width " + width + ", height " + height);
}
#Override
protected void onDraw(Canvas canvas) {
//Draw the background
background.setColor(getResources().getColor(R.color.background));
canvas.drawRect(0, 0, getWidth(), getHeight(), background);
//Draw the board
//Define colors for grid lines
dark.setColor(getResources().getColor(Color.DKGRAY));
light.setColor(getResources().getColor(Color.LTGRAY));
hilite.setColor(getResources().getColor(Color.WHITE));
for (int i = 0; i < 10; i++) {
Log.d(TAG, "Drawing...");
canvas.drawLine(0, i * height - 1, getWidth(), i * height - 1, light);
canvas.drawLine(0, i * width - 1, getHeight(), i * width - 1, light);
canvas.drawLine(0, i * height, getWidth(), i * height, hilite);
canvas.drawLine(0, i * width, getHeight(), i * width, hilite);
canvas.drawLine(0, i * height + 1, getWidth(), i * height + 1, dark);
canvas.drawLine(0, i * width + 1, getHeight(), i * width + 1, dark);
}
}
}
I have tried comparing the author's code to mine and except where I am not implementing features he is the codes seem to be matching.
However, the Log.d(TAG, "onSizeChanged: width " + width + ", height " + height); does not appear in LogCat so I assume this function is simply never called and I do not understand why.
You just create an instance of your GameView but you do not add it to your activity. Do this by using
setContentView(gameView);
in your onCreate method.
You need to set the view to the activity with setContentView(gameView) in onCreate of Game Activity.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "Game.onCreate called");
gameView = new GameView(this);
setContentView(gameView); // missing
...//rest of the code

Categories

Resources