I'm not getting any errors when I run my code, but nothing happens I touch the screen. The value of the global variable select should change but nothing happens.
Here is the code
public class NonmultiplierSixGame extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_nonmultiplier_six_game);
}
}
activity_nonmultiplier_six_game:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
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="com.example.alexandermain.example_5.NonmultiplierSixGame">
<com.example.alexandermain.example_5.views.NonmultiplierSixView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/nonmultiplierSixView"
android:background="#color/colorPrimary"
/>
</android.support.constraint.ConstraintLayout>
NonmultiplierSixView class:
public class NonmultiplierSixView extends View implements View.OnTouchListener{
#Override
protected void onDraw(Canvas canvas){
//bunch of shapes
}
#Override
public boolean onTouch(View v, MotionEvent event) {
switch(event.getAction()) {
case MotionEvent.ACTION_DOWN:
Globals.SetSelect(1);
break;
case MotionEvent.ACTION_UP:
Globals.SetSelect(2);
break;
}
return true;
}
public NonmultiplierSixView(Context context, AttributeSet attrs) {
super(context, attrs);
}
}
Edit:
Here is the Globals class
public class Globals {
public static int select=-2;
public static void SetSelect(int t) {
select = t;
}
public static int GetSelect() {
return(select);
}
}
When you implement OntouchListener, you need to setThe listener on your Context.
Simply add it in your constructor:
It should be like this:
public NonmultiplierSixView(Context context, AttributeSet attrs) {
super(context, attrs);
setOnTouchListener(this);
}
I am a pretty inexperienced programmer but I created onTouch listener earlier today which works fine,
Try to change the onTouch method to something like this:
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
Globals.SetSelect(1);
return false;
case MotionEvent.ACTION_UP:
Globals.SetSelect(2);
return false;
}
return false;
}
I'm sorry in advance if it doesn't work for you..
There is no need to implements View.OnTouchListener, View class already have its onTouchEvent(MotionEvent event) method . Try this:
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
break;
}
return true;
}
It will definately work. and check this also.
The onDraw method repeats continuously.
So maybe, even if you touch your object, it is everytime redrawn to its initial position because of the onDraw.
So what you wanna do is for example set a boolean isPostionned, so your object will be drawn on initial position only 1 time.
so the boolean will be initially false, and then you set it true once your item is drawn.
For example: declare in your NonmultiplierSixView class
boolean isPositionned = false;
than in onDraw:
if (!isPositionned){
//code to position you object
isPositionned = true;
}
(This is in case your intention is to move the shape)
Related
I disable swipe the ViewPager with TabLayout as below:
public class NonScrollableViewPager extends ViewPager {
public NonScrollableViewPager(Context context) {
super(context);
init(context, null);
}
public NonScrollableViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
}
#Override
public boolean onInterceptTouchEvent(MotionEvent event) {
// Never allow swiping to switch between pages
return false;
}
#Override
public boolean onTouchEvent(MotionEvent event) {
// Never allow swiping to switch between pages
return false;
}
}
How to prevent other tabs clickable when select one of tabs, then computation complected then enable the clickable. ViewPager.setClickable(false) and setEnabled() don't work
disable clickable
// do something
enable clickable
How to do that?
I am assuming that you are using TabLayout along with ViewPager. So, you need to implement as follows
LinearLayout tabStrip = ((LinearLayout) your_tab_layout.getChildAt(0));
for(int i = 0; i < tabStrip.getChildCount(); i++) {
tabStrip.getChildAt(i).setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
return true;
}
});
}
For API 24 and above
your_tab_layout.clearOnTabSelectedListeners();
Hope this helps
I am making a project. It draws concentric circles in android canvas. When the user drags the screen, all the circles move accordingly. Here is my code so far.
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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=".MainActivity"
android:background="#android:color/white">
<RelativeLayout
android:id="#+id/scrollableSpace"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true">
<project.myProject.DrawOrbit
android:id="#+id/orbitsRegion"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true" />
</RelativeLayout>
</RelativeLayout>
MainActivity.java
public class MainActivity extends AppCompatActivity implements View.OnTouchListener
{
PointF center;
center.x=500;center.y=500;
float radius[]={100,200,300,400,500};
DrawOrbit orbit;
int startX=0,startY=0,currentX=0,currentY=0;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RelativeLayout layout=(RelativeLayout)findViewById(R.id.scrollableSpace);
orbit.draw(center,radius);
layout.setOnTouchListener(this);
}
#Override
public boolean onTouch(View v, MotionEvent motionEvent)
{
final int action= motionEvent.getAction();
switch(action & MotionEvent.ACTION_MASK)
{
case MotionEvent.ACTION_DOWN:
{
startX=(int)motionEvent.getRawX();
startY=(int)motionEvent.getRawY();
break;
}
case MotionEvent.ACTION_MOVE:
{
currentX=(int)motionEvent.getRawX();
currentY=(int)motionEvent.getRawY();
float diffX=currentX-startX;
float diffY=currentY-startY;
startX=currentX;
startY=currentY;
center.x+=diffX;
center.y+=diffY;
orbit.draw(center,radius);
break;
}
}
return true;
}
}
DrawOrbit.java
public class DrawOrbit extends View
{
PointF center;
float radius[];
public DrawOrbit(Context context) {
super(context);
}
public DrawOrbit(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
}
public DrawOrbit(Context context, #Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
paint.setColor(Color.BLACK);
paint.setStrokeWidth(2);
paint.setStyle(Paint.Style.STROKE);
int len=radius.length;
for(int a=0;a<len;a++)
{
canvas.drawCircle(center.x,center.y,radius[a],paint);
}
}
public void draw(PointF center, float radius[])
{
this.center=center;
this.radius=radius;
invalidate();
requestLayout();
}
}
What I want to do is that the circles should appear one by one. First the inner most circle then the next one after some delay then the next and so on. The same effect should be seen when the screen is dragged. How can I achieve this? Any help will be appreciated.
What you're looking for is a timeout. I'd suggest creating a new thread to draw everything, and start by drawing the first circle, have the method look like this:
public void drawCircle() {
//Draw logic
TimeUnit.SECONDS.sleep(3);
drawNextCircle();
}
//Assuming on java 1.8+
Thread thread = new Thread() => {
drawCircle();
}
What this will do is have the thread sleep for 3 seconds, and then continue normal operation after the time period is up. You can change it to other measurements of time such as TimeUnit.MILLISECONDS or TimeUnit.MINUTES as well.
edit: You likely won't want this in your main thread, as it will stop the ENTIRE application from working for however long you put the thread on timeout, so it's almost essential for this to work that you put it in a separate thread.
edit 2: It would make more sense to add a separate util method to timeout and then call another method via reflection than the above code, but the same code would be needed.
Figured out the answer to my own question. I had to use a Handler, multiplied the delay with the for-loop variable and made 1 then 2 then so on.. circles to get the desired effect. Here is the code.
MainActivity.java
public class MainActivity extends AppCompatActivity implements View.OnTouchListener
{
PointF center;
center.x=500;center.y=500;
float radius[]={100,200,300,400,500};
DrawOrbit orbit;
int startX=0,startY=0,currentX=0,currentY=0;
Handler handler1 = new Handler();
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RelativeLayout layout=(RelativeLayout)findViewById(R.id.scrollableSpace);
for (int a = 0; a<radius.length ;a++)
{
final int index=a;
handler1.postDelayed(new Runnable() {
#Override
public void run() {
orbit.draw(center,radius,index);
}
}, 300 * a);
}
layout.setOnTouchListener(this);
}
#Override
public boolean onTouch(View v, MotionEvent motionEvent)
{
final int action= motionEvent.getAction();
switch(action & MotionEvent.ACTION_MASK)
{
case MotionEvent.ACTION_DOWN:
{
startX=(int)motionEvent.getRawX();
startY=(int)motionEvent.getRawY();
break;
}
case MotionEvent.ACTION_MOVE:
{
currentX=(int)motionEvent.getRawX();
currentY=(int)motionEvent.getRawY();
float diffX=currentX-startX;
float diffY=currentY-startY;
startX=currentX;
startY=currentY;
center.x+=diffX;
center.y+=diffY;
break;
}
case MotionEvent.ACTION_UP:
{
for (int a = 0; a<radius.length ;a++)
{
final int index=a;
handler1.postDelayed(new Runnable() {
#Override
public void run() {
orbit.draw(center,radius,index);
}
}, 300 * a);
}
break;
}
}
return true;
}
}
DrawOrbit.java
public class DrawOrbit extends View
{
PointF center;
float radius[];
int index;
public DrawOrbit(Context context) {
super(context);
}
public DrawOrbit(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
}
public DrawOrbit(Context context, #Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
paint.setColor(Color.BLACK);
paint.setStrokeWidth(2);
paint.setStyle(Paint.Style.STROKE);
int len=radius.length;
for(int a=0;a<index;a++)
{
canvas.drawCircle(center.x,center.y,radius[a],paint);
}
}
public void draw(PointF center, float radius[],int index)
{
this.center=center;
this.radius=radius;
this.index=index;
invalidate();
requestLayout();
}
}
I have a Tabbed Activity: a user can swipe to the right or to the left to change the screens. At some point I want to record an audio and while it is being recorder the user is not supposed to change the screens.
Question: How to restrict a user from changing screens (swiping) in ViewPager?
I tried to figure out how to do that using ViewPager API but I didn't manage to find a proper way (there are hundreds or may be even thousand methods in ViewPager none of which is likely to do what I want).
You can extend the ViewPager class and use this code.
public class LockableViewPager extends ViewPager {
private boolean swipeable;
public LockableViewPager(Context context) {
super(context);
}
public LockableViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
this.swipeable = true;
}
#Override
public boolean onInterceptTouchEvent(MotionEvent event) {
return this.swipeable && super.onInterceptTouchEvent(event);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
return this.swipeable && super.onTouchEvent(event);
}
public void setSwipeable(boolean swipeable) {
this.swipeable = swipeable;
}
}
Then in your Fragment or Activity you can just call mViewPager.setSwipeable(false); to make it unswipeable.
Create a custom viewPager like below
public class CustomViewPager extends ViewPager {
private boolean enabled = true;
public CustomViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
enabled = true;
}
#Override
public boolean onInterceptTouchEvent(MotionEvent arg0) {
if (enabled) {
return super.onInterceptTouchEvent(arg0);
} else {
return false;
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (this.enabled) {
return super.onTouchEvent(event);
}
return false;
}
public void setPagingEnabled(boolean enabled) {
this.enabled = enabled;
}
}
Then simply call viewPager.setPagingEnabled(false);
I have a problem. I have my own scrollview, but it doesn't work. The scrollbar appears, but when I try to use it doesn't work. I have tried a lot of things, but none work. The code is:
#SuppressLint("ClickableViewAccessibility") public class myScrollView extends ScrollView {
private boolean enableScrolling = true;
public boolean isEnableScrolling() {
return enableScrolling;
}
public void setEnableScrolling(boolean enableScrolling) {
this.enableScrolling = enableScrolling;
}
public myScrollView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public myScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public myScrollView(Context context) {
super(context);
}
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (isEnableScrolling()) {
return super.onInterceptTouchEvent(ev);
} else {
return false;
}
}
#Override
public boolean onTouchEvent(MotionEvent ev) {
if (isEnableScrolling()) {
return super.onInterceptTouchEvent(ev);
} else {
return false;
}
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// TODO Auto-generated method stub
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(getMeasuredWidth(), getMeasuredHeight());
}
}
Inside of this scroll, I have a relativeLayout and inside of this a View. In the View I draw some bitmaps. They number more than it can display the screen.
The XML is:
<com.edjume.myScrollView
android:id="#+id/scroll_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="#+id/table">
<RelativeLayout
android:id="#+id/table"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
</RelativeLayout>
</com.edjume.myScrollView>
And in the activity I use:
RelativeLayout ll = (RelativeLayout) findViewById(R.id.table);
ll.addView(new Table(this));
And finally, in my View (Table) has a OnDraw() and a onTouchEvent(). In the onTouchEvent I use the options ACTION_DOWN, ACTION_MOVE and ACTION_UP.
I believe
#Override
public boolean onTouchEvent(MotionEvent ev) {
if (isEnableScrolling()) {
return super.onInterceptTouchEvent(ev);
} else {
return false;
}
}
should be:
#Override
public boolean onTouchEvent(MotionEvent ev) {
if (isEnableScrolling()) {
return super.onTouchEvent(ev);
} else {
return false;
}
}
I'm trying to draw some shapes onto a SurfaceView from within a thread, but nothing is being rendered to the screen. I've looked at similar questions by people having the same problem, but none of the answers have led me to a solution, suggesting a different cause in my particular case.
I've created a simplified version of my code to demonstrate the problem. Rendering is handled by the RenderingTestView class, which implements a custom view derived from SurfaceView. The rendering thread is implemented as a Runnable inside RenderingTestView:
package com.example.renderingtest.app;
import android.content.Context;
import android.graphics.*;
import android.os.Build;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class RenderingTestView extends SurfaceView {
private SurfaceHolder holder;
private Paint paint;
private boolean surfaceCreated = false;
private Thread videoThread;
public RenderingTestView(Context context) {
super(context);
init_view(context);
}
public RenderingTestView(Context context, AttributeSet attrs) {
super(context, attrs);
init_view(context);
}
public RenderingTestView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init_view(context);
}
private void init_view(Context context)
{
if (Build.VERSION.SDK_INT >= 11)
setLayerType(android.view.View.LAYER_TYPE_SOFTWARE, null);
paint = new Paint();
paint.setColor(Color.RED);
holder = getHolder();
holder.addCallback(new SurfaceHolder.Callback() {
#Override
public void surfaceCreated(SurfaceHolder holder) {
surfaceCreated = true;
videoThread = new Thread(videoRunnable);
videoThread.start();
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
// do nothing
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
surfaceCreated = false;
}
});
}
private Runnable videoRunnable = new Runnable() {
#Override
public void run() {
Thread.currentThread().setPriority(Thread.NORM_PRIORITY);
while (true) {
if (!surfaceCreated || !holder.getSurface().isValid())
continue;
Canvas c = holder.lockCanvas(null);
try {
synchronized (holder) {
if (c != null)
Draw(c);
}
}
finally {
if (c != null)
holder.unlockCanvasAndPost(c);
}
}
}
};
protected void Draw(Canvas canvas)
{
canvas.drawCircle(0, 0, 100, paint);
}
}
Placing a breakpoint inside Draw() confirms that it's being called successfully.
The layout file looks like this:
<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:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="#dimen/activity_vertical_margin"
tools:context="com.example.renderingtest.app.RenderingTest" android:background="#000000">
<com.example.renderingtest.app.RenderingTest
android:id="#+id/renderingTestView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true" android:layout_alignParentTop="true"/>
</RelativeLayout>
Overriding onDraw() in RenderingTestView, like this:
#Override
public void onDraw(Canvas canvas)
{
super.onDraw(canvas);
Draw(canvas);
}
... and calling setWillNotDraw(false) inside init_view() does in fact produce the desired output, but I want to render from inside the Runnable rather than wait for invalidate() to produce a call to onDraw().
After further testing, I've discovered the problem is caused by the following code:
if (Build.VERSION.SDK_INT >= 11)
setLayerType(android.view.View.LAYER_TYPE_SOFTWARE, null);
It turns out calling setLayerType() as above somehow prevents SurfaceView from rendering anything onto the Canvas, and is in any case unnecessary since SurfaceView rendering is always performed in software. When first testing my draw calls I was using a regular View rather than a SurfaceView, and the offending lines were carried over from that.