I have a class GameActivityas follows (I just post the relevant part):
public class GameActivity extends AppCompatActivity {
// initiate variables
private GameView mGameView;
private Display mDisplay;
private Point mSize;
public static int window_width = 0;
public static int window_height = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
mDisplay = getWindowManager().getDefaultDisplay();
mSize = new Point();
mDisplay.getSize(mSize);
window_width = mSize.x;
window_height = mSize.y;
// initialize game view object
mGameView = new GameView(this);
// adding it to the content view
//setContentView(mGameView);
setContentView(R.layout.activity_game);
}
And I have the class GameView as follows with two constructors because of the custom view (also just the relevant parts to keep it clear):
private Context mContext;
//These objects will be used for drawing
private SurfaceHolder mSurfaceHolder;
private Paint mPaint;
public GameView(Context context){
super(context);
Log.d("TEST","Constructor 1");
init(context, null);
// clear all lists
...
// create object of map in beginning of game
...
// create objects of HQs
...
// create other sprite objects and add them to lists
...
}
public GameView(Context context, AttributeSet attrs) {
super(context, attrs);
Log.d("TEST","Constructor 2");
init(context, attrs);
}
And I call in both of the constructors the init() method
private void init(Context context, AttributeSet attrs) {
mContext = context;
mSurfaceHolder = getHolder();
mPaint = new Paint();
mPaint.setColor(Color.DKGRAY);
}
My run() is like this:
#Override
public void run(){
Log.d("TEST","RUN");
long current_time = 0;
long old_time;
while (playing) {
old_time = current_time;
// update the game
update();
//to draw the frame
//onDraw(canvas);
draw();
//to control (lets the game sleep for some milliseconds)
control();
current_time = SystemClock.elapsedRealtime();
frametime = current_time - old_time;
framerate = 1000/ (current_time - old_time);
}
}
And the draw() (where the mistake happens) is like this:
private void draw() {
// BUG: mSurfaceHolder.getSurface.isValid ist niemals valid
Canvas canvas;
//if(true){
//checking if surface is valid
if (mSurfaceHolder.getSurface().isValid()) {
Log.d("Test","DRAW");
//locking the canvas
canvas = mSurfaceHolder.lockCanvas();
//drawing a background color for canvas
canvas.drawColor(Color.GREEN);
// call draw methods here
// bigger objects should be called before smaller objects for visibility
draw_ground(canvas);
draw_hq(canvas);
draw_soldiers(canvas);
draw_bullets(canvas);
draw_HUD(canvas);
//Unlocking the canvas
mSurfaceHolder.unlockCanvasAndPost(canvas);
}
}
No the question is:
If I in the first class GameActivity pass the object mGameView of the class GameView to setContentView everything is fine and the draw() methods works normal which means mSurfaceHolder.getSurface().isValid()) is valid.
But if I put in the first class setContentView(R.layout.activity_game); then mSurfaceHolder.getSurface().isValid()) is never valid. Everything else works (e.g. I hear the game sound) but he doesn't draw. If I don't check for mSurfaceHolder.getSurface().isValid()) then the game crashes because in the code below in draw() the canvas is empty.
My aim is to create a custom view and overlay this with buttons.
Here is the XML:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".GameActivity">
<!--Test-->
<com.example.mirco.battlefront.GameView
android:id="#+id/gameView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<Button
android:id="#+id/button"
android:layout_width="119dp"
android:layout_height="wrap_content"
android:text="Button" />
<!--Test-->
</FrameLayout>
The XML seems to be correct because Android Studio recognizes it (custom view with overlayed button). But he doesn't draw in it.
Like I said with setContentView(mGameView); everything is fine except that I only have one view where I can't overlay buttons and so on which is not what I want.
What am I doing wrong? I tried to follow that LINK as good as possible. I am trying for days now to solve this but also can't find the solution anywhere.
Instead of
mGameView = new GameView(this);
// adding it to the content view
//setContentView(mGameView);
setContentView(R.layout.activity_game);
You should do
setContentView(R.layout.activity_game);
mGameView = (GameView)findViewById (R.id.gameView);
Then the mGameview is the one in your layout.
Related
I am trying to create the green shape and add text and an image on top of the green shape. Like this example:
I created the this example in photoshop and I tried to use it as an <ImageView> but the image always look blurry and so, I decided to re-create it using .xml
I know how to create a circle, something like this:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:innerRadius="0dp"
android:shape="ring"
android:thicknessRatio="1.9"
android:useLevel="false" >
<solid android:color="#android:color/transparent" />
<stroke
android:width="10dp"
android:color="#android:color/white" />
</shape>
Thanks,
You have several options but if I understand you correctly you would like to have one View which will fill the whole screen, show some text in addition to the picture and last not least have this curved background.
To achieve this, one can create a custom View which extends from ImageView (or as Android Studio recommends it, from android.support.v7.widget.AppCompatImageView). Extending from ImageView means we'll have to take care of the background and the text, handling the picture will be no problem.
IMO it's better to give the custom View a set of parameters and have it draw the background using a Path than to use a ShapeDrawable because this way one can first evaluate the View's bounds and then determine where exactly the curve should be drawn.
First, let's introduce some dimension values in res/values/dimens.xml
<dimen name="clipped_circle_deviation">100dp</dimen>
<dimen name="clipped_circle_padding_top">60dp</dimen>
Then, the Activity layout:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.example.customviews.views.ClippedCircleView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="#drawable/test"
android:paddingTop="#dimen/clipped_circle_padding_top"
android:scaleType="center"/>
</RelativeLayout>
The picture I used for testing:
And what it looks like (I'm sure the text needs some fine tuning but that's another question)
ClippedCircleView.java
public class ClippedCircleView extends android.support.v7.widget.AppCompatImageView {
public static final String TAG = "ClippedCircle";
private static final int INNER_EDGE_WEIGHT = 2;
private static final int OUTER_EDGE_WEIGHT = 3;
private int measuredWidth;
private int measuredHeight;
private Paint innerPaint;
private Paint outerPaint,;
private Paint textPaint;
private Path path;
public ClippedCircleView(Context context) {
super(context);
init();
}
public ClippedCircleView(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
public ClippedCircleView(Context context, #Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init(){
setWillNotDraw(false);
path = new Path();
innerPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
innerPaint.setColor(Color.GREEN);
innerPaint.setStyle(Paint.Style.FILL);
outerPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
outerPaint.setColor(Color.WHITE);
outerPaint.setStyle(Paint.Style.FILL);
textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
textPaint.setColor(Color.WHITE);
textPaint.setStyle(Paint.Style.FILL);
textPaint.setTextSize(getResources().getDimensionPixelSize(R.dimen.clipped_circle_textsize));
}
#Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
measuredWidth = right - left;
measuredHeight = bottom - top;
float innerEdgeLength = INNER_EDGE_WEIGHT/ (OUTER_EDGE_WEIGHT * 1.0f) * measuredHeight;
path.moveTo(0,0);
path.lineTo(0, innerEdgeLength);
float deviation = getResources().getDimensionPixelSize(R.dimen.clipped_circle_deviation);
path.quadTo(measuredWidth*0.5f, innerEdgeLength + deviation, measuredWidth, innerEdgeLength);
path.lineTo(measuredWidth, 0);
path.lineTo(0,0);
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawRect(0, 0, measuredWidth, measuredHeight, outerPaint);
canvas.drawPath(path, innerPaint);
canvas.drawText("Hello!", 32, 80, textPaint);
canvas.drawText("Welcome to", 32, 160, textPaint);
canvas.drawText("My App", 32, 240, textPaint);
super.onDraw(canvas);
}
}
There is no way to directly write text in shape drawable except converting it to bitmap then write the text. If you really want to create it with Drawable, you should do it using Adobe Illustrator and export it as svg. Then it is possible to import svg as Android Vector Drawable (File -> New -> Vector Asset -> Local file -> ...).
So I've got this problem in my custom view. I'm trying to create a custom RelativeLayout with an infinite scrolling animation. To achieve this, I've created a layout backgroundscrollrelativelayout.xml like so:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/mainTile"/>
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/topTile" />
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/leftTile" />
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/diagonalTile" />
</RelativeLayout>
The idea is that the ImageViews will translate their position on an animation update callback.
I've created the BackgroundScrollRelativeLayout.java like so:
public class BackgroundScrollRelativeLayout extends RelativeLayout {
final int layoutToUse = R.layout.backgroundscrollrelativelayout;
final int mainTileId = R.id.mainTile;
final int leftTileId = R.id.leftTile;
final int topTileId = R.id.topTile;
final int diagonalTileId = R.id.diagonalTile;
final float valueStart = 0.0f;
final float valueEnd = 1.0f;
final long animationDuration = 50000L;
private Context mContext;
private ValueAnimator scrollAnimator;
private ImageView mainTile;
private ImageView leftTile;
private ImageView topTile;
private ImageView diagonalTile;
public BackgroundScrollRelativeLayout(Context context) {
super(context);
mContext = context;
acquireViewsInLayout();
initializeAnimator();
scrollAnimator.start();
}
public BackgroundScrollRelativeLayout(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
acquireViewsInLayout();
initializeAnimator();
scrollAnimator.start();
}
public BackgroundScrollRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mContext = context;
acquireViewsInLayout();
initializeAnimator();
scrollAnimator.start();
}
#Override
public void setBackgroundColor(int color) {
// Not supported
}
#Override
public void setBackgroundResource(int resid) {
// Not supported
}
#Override
public void setBackground(Drawable background) {
mainTile.setBackground(background);
leftTile.setBackground(background);
}
/*
#Override
public void setBackgroundDrawable(Drawable background) {
//super.setBackgroundDrawable(background);
//mainTile.setBackground(background);
//leftTile.setBackground(background);
}*/
// Intent: Inflate the layout associated with this View
private void inflateLayout(){
// TO inflateLayout, we connect the inflater to context, then we call inflate the layout associated
// with this view
//LayoutInflater inflater = LayoutInflater.from(mContext);
//inflater.inflate(layoutToUse, this);
inflate(getContext(), layoutToUse, this);
}
// Intent: Find all Views in Layout
private void findAllViewsById(){
mainTile = (ImageView)this.findViewById(mainTileId);
leftTile = (ImageView)this.findViewById(leftTileId);
topTile = (ImageView)this.findViewById(topTileId);
diagonalTile = (ImageView)this.findViewById(diagonalTileId);
}
// Intent: Concretely acquire all Views in Layout
private void acquireViewsInLayout(){
// TO acquireViewsInLayout, we inflate the layout,
// then we find the view of each known view id and save the view
inflateLayout();
findAllViewsById();
}
// Intent: Initialize animator properties
private void initializeAnimator(){
// TO initializeAnimator, we set how the animator will keep track of animation,
// then we set the animation repeat type, then we set the type of interpolation,
// then we set the animation duration, then we apply animation update listener
scrollAnimator = ValueAnimator.ofFloat(valueStart, valueEnd);
scrollAnimator.setRepeatCount(ValueAnimator.INFINITE);
scrollAnimator.setInterpolator(new LinearInterpolator());
scrollAnimator.setDuration(animationDuration);
addScrollAnimatorUpdateListener();
}
// Intent: Add an update listener to the scroll animator
private void addScrollAnimatorUpdateListener(){
// TO addScrollAnimatorUpdateListener, we add an update listener to scroll animator
scrollAnimator.addUpdateListener( new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
// Do something...
updateScrollAnimation();
}
});
}
private void updateScrollAnimation(){
float progress = (float)scrollAnimator.getAnimatedValue();
float widthOfTile = mainTile.getWidth();
float moveInXAxis = widthOfTile * progress;
mainTile.setTranslationX(moveInXAxis);
leftTile.setTranslationX(moveInXAxis - widthOfTile);
// Ignore the rest for now
topTile.setTranslationY(-1.0f);
diagonalTile.setTranslationX(-1.0f);
diagonalTile.setTranslationY(-1.0f);
}
}
I use my custom view like so in an activity:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context="com.martianstudio.adivinaque.AppSettingsActivity">
<com.martianstudio.adivinaque.BackgroundScrollRelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/main_activity_animation_icon" />
</RelativeLayout>
The goal of this is to allowing the user to specify the background that they want to scroll with android:background. I do not want the parent RelativeLayout to take on this drawable as a background. Instead, I want the ImageViews to set the drawable as the background. I have overridden the setBackground in my custom view so that only the ImageViews set the drawable as the background and not the RelativeLayout (as it would by default).
#Override
public void setBackground(Drawable background) {
mainTile.setBackground(background);
leftTile.setBackground(background);
}
However, I get this error:
java.lang.NullPointerException at com.martianstudio.adivinaque.BackgroundScrollRelativeLayout.setBackground
This says that mainTile in setBackground has not been set (it is null). In my findAllViewsById() I explicitly write this.mainTile = (ImageView)this.findViewById(mainTileId);, where mainTileId = R.id.mainTile, and I inflate the layout in inflateLayout(). Both of these methods are called in the constructors of the class. It seems to me that for some reason, it cannot find the ImageView with the mainTile Id when I override the setBackground method like I do. If I don't override the setBackground method, I do not get a NullPointerException, however, it defaults to the default setBackground method, which is what I do not want. Am I missing somthing?
Any help will be appreciated :). Thank you!
I'm writing a simple UI activity, the intention of which is to create an offscreen OpenGL surface and have a GL test render into it in a background GL thread. The rendering should start at a click of the button and the TextView should display some environment information (OpenGL version, etc.) as well as the test progress (as it may take a while) and result. In the sample I'm providing I have a 5 second delay in the 'run' function of the Runnable, but in the actual app code I have a JNI call to a native library that has the GL rendering code.
I've verified that the problem I'm experiencing exists with the 5 second delay as well as the original JNI call. The problem is that while the test is running (a 5 second delay in this sample), UI seems to be frozen and does not update until the test is done. The text that I'm setting to my TextView only appears when the test is finished. I thought that "queueEvent(new TestRunnable());" starts the runnable in a separate GL thread so that UI thread can continue with no interruptions, but it does not seem to be the case, or something else is missing. Do you guys/gals have any idea what I'm doing wrong?
The simplified layout:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:keepScreenOn="true" android:orientation="vertical"
android:layout_width="fill_parent" android:layout_height="fill_parent">
<Button
android:id="#+id/startTestButton" android:textSize="18sp"
android:layout_width="fill_parent" android:layout_height="wrap_content"
android:text="#string/startTestButton" android:onClick="onStartTestClick"/>
<ScrollView android:layout_width="wrap_content" android:layout_height="wrap_content">
<TextView
android:id="#+id/logView" android:textSize="18sp"
android:layout_width="wrap_content" android:layout_height="wrap_content" />
</ScrollView>
<com.company.name.MyView
android:id="#+id/myView"
android:layout_width="match_parent" android:layout_height="match_parent"/>
</LinearLayout>
The simplified activity class is defined as follows:
public class MyActivity extends Activity
{
private String m_LogText = null;
private Button m_StartTestButton = null;
private TextView m_TestLog = null;
private MyView m_SurfaceView;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
m_StartTestButton = (Button) findViewById(R.id.startTestButton);
m_SurfaceView = (MyView) findViewById(R.id.myView);
m_TestLog = (TextView) findViewById(R.id.logView);
// Check for OpenGL 2.0 support.
ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
ConfigurationInfo info = am.getDeviceConfigurationInfo();
m_LogText = "Open GLES version detected: " + Integer.toHexString(info.reqGlEsVersion) + "\n";
m_TestLog.setText(m_LogText);
}
public void onStartTestClick(View view)
{
//
// This text here does not appear until the end of the test:
//
m_LogText += "\nStarting the test: default\n";
m_LogText += "Test is running, please wait...\n";
m_TestLog.setText(m_LogText);
m_SurfaceView.StartTest();
}
}
Simplified MyView class is defined as follows:
public class MyView extends GLSurfaceView
{
private TestRenderer m_Renderer = null;
private class TestRenderer implements GLSurfaceView.Renderer
{
public void onDrawFrame(GL10 gl) { }
public void onSurfaceChanged(GL10 gl, int width, int height) { }
public void onSurfaceCreated(GL10 gl, EGLConfig config) { }
class TestRunnable implements Runnable
{
public void run()
{
try
{
Thread.sleep(5000);
}
catch(InterruptedException ex)
{
Thread.currentThread().interrupt();
}
}
}
public void StartTest()
{
queueEvent(new TestRunnable());
}
}
public MyView(Context context)
{
this(context, null);
}
public MyView(Context context, AttributeSet attrs)
{
super(context, attrs);
m_Renderer = new TestRenderer();
setRenderer(m_Renderer);
}
public void StartTest()
{
m_Renderer.StartTest();
}
}
I'm making an app that just displays a clock, but I want is so that everytime a user touches the screen it changes the color of the text (from a list of preselected colors in a colors.xml file) but I haven't got a clue where to start. Can someone point me in the right direction?
Here's the main activity:
public class MainActivity extends Activity {
private static final Random RANDOM = new Random();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setContentView(R.layout.activity_main);
Handler handler = new RandomMoveHandler((TextView) findViewById(R.id.digitalClock1));
handler.sendEmptyMessage(0);
}
// Make the handler subclass static because of this: http://stackoverflow.com/a/11408340/111777
private static class RandomMoveHandler extends Handler {
private final WeakReference<TextView> textViewWeakReference;
private RandomMoveHandler(TextView textView) {
this.textViewWeakReference = new WeakReference<TextView>(textView);
}
#Override
public void handleMessage(Message msg) {
TextView textView = textViewWeakReference.get();
if (textView == null) {
Log.i(TAG, "WeakReference is gone so giving up.");
return;
}
int x = RANDOM.nextInt(350 - 100);
int y = RANDOM.nextInt(800 - 100);
Log.i(TAG, String.format("Moving text view to (%d, %d)", x, y));
textView.setX(x);
textView.setY(y);
//change the text position here
this.sendEmptyMessageDelayed(0, 30000);
}
}
private static final String TAG = MainActivity.class.getSimpleName();
}
and here's the layout xml:
<AbsoluteLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
tools:context=".MainActivity"
android:background="#color/black" >
<DigitalClock
android:id="#+id/digitalClock1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="DigitalClock"
android:textColor="#color/ics_blue"
android:textSize="28sp" />
I haven't making deal with DigitalClock but I think, at first, you should reference DigitalClock variable, not TextView. And second, to intercept touch event you need to override onTouckEvent method of your activity, it will callback everytime user touches the screen.
You should follow these steps
Use a TimerTask to.continusly show the time
Implement a touchlistener on that clock view
like this
view.setOnTouchListener
Make an array Colors like this
int[] colr={Color.BLACK,Color.BLUE};
and use random index in your touch event andset it as your color of the view
I'm unable to call methods of a custom view ("canvasview") from the Activity that sets the layout including the view. I can't even call canvasview's "getters" from the activity.
Also, I'm passing the view to a custom class (that does not extend Activity), and I can't call canvasview's methods also from my custom class.
I'm not sure what I'm doing wrong...
GameActivity.java:
public class GameActivity extends Activity implements OnClickListener
{
private View canvasview;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.game_layout);
canvasview = (View) findViewById(R.id.canvasview);
// Eclipse displays ERROR con those 2 method calls:
int w = canvasview.get_canvaswidth();
int h = canvasview.get_canvasheight();
(...)
game_layout.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/LinearLayout2"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".GameActivity" >
(...)
<com.example.test.CanvasView
android:id="#+id/canvasview"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
CanvasView.java:
public class CanvasView extends View
{
private Context context;
private View view;
private int canvaswidth;
private int canvasheight;
public CanvasView(Context context, AttributeSet attrs)
{
super(context, attrs);
this.context = context;
this.view = this;
}
#Override
protected void onSizeChanged(int width, int height,
int old_width, int old_height)
{
this.canvaswidth = width;
this.canvasheight = height;
super.onSizeChanged(width, height, old_width, old_height);
}
public int get_canvaswidth()
{
return this.canvaswidth;
}
public int get_canvasheight()
{
return this.canvasheight;
}
I'm quite confused with this :?
I also have another class (it does not extend "Activity") that receives in the constructor a reference to canvasview and is also unable to "resolve" it :?
Thanks, sorry if the question is too obvious, I'm starting with Java and those kind of things are quite confusing to me ...
EDIT:
While at bed (03:00AM), thinking about it, I've noticed that Eclipse marks the line as an error because the View object does not really have the method get_canvaswidth(). Only the child "CanvasView" method has it. Thus, my problem can be solved with upcast:
int w = ((CanvasView) canvasview).get_canvaswidth();
I mean that I receive a view as parameter, but as I now it's really a view child, I should be able to use upcast to call "child's" methods. Now eclipse does not generate errors but w and h always report 0 :-? . I've also tested of not using upcast as has been suggested in an answer, and sending and receiving CanvasView objects in the calls and I also get 0 for both :?
private View canvasview;
No matter what is stored in canvasview you can only call methods defined by the variable type. You need to change this line.
private CanvasView canvasview;