J'ai un problème où j'ai une vue de surface à l'intérieur d'un pager de vue. Tout va bien jusqu'à ce que j'appuie sur l'un des onglets. Le pager de la vue défile, mais la page de l'écran suivant est écrasée.Surface vue écrasée à l'intérieur de la vue téléavertisseur
Si je quitte l'application et revenir en elle, la deuxième page rendra bien. Ensuite, si je presse pour revenir au premier, il écrase à nouveau. Je ne sais pas du tout quelle partie de la mise en page va mal, et pour autant que je sache, la hauteur réelle de la vue de surface ne change pas, comme lorsque j'utilise la méthode .getHeight() sur la vue de surface retourne toujours la même valeur.
Voici ma classe de pager vue:
public class PendulumViewPager extends ViewPager {
public PendulumViewPager(Context context) {
super(context);
}
public PendulumViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
return false;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return false;
}
Voici le fragment étant ajouté au téléavertisseur de vue:
public class SurfacePanelFragment extends Fragment{
private int TYPE = 1;
private SurfacePanel panel;
public void setType(int type){
TYPE = type;
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_surface_panel, container, false);
panel = view.findViewById(R.id.canvas);
panel.setType(TYPE);
return view;
}
public void startStopPendulum(ImageButton view){
panel.startStop(view);
}
public void stopPendulum(){
panel.stop();
}
@Override
public void onResume() {
if(getUserVisibleHint()) {
panel.delayStartThread();
((MainActivity)getActivity()).getStopButton().setImageDrawable(getContext().getResources().getDrawable(R.drawable.ic_pause_white_48dp));
}
super.onResume();
}
@Override
public void onPause() {
panel.terminate();
super.onPause();
}
public void stopRendering(){
panel.stopRendering();
}
public void startRendering(){
panel.startRendering();
}
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if(panel != null) {
if (isVisibleToUser) {
panel.delayStartThread();
((MainActivity)getActivity()).getStopButton().setImageDrawable(getContext().getResources().getDrawable(R.drawable.ic_pause_white_48dp));
Log.i("WP", String.valueOf(panel.getHeight()));
} else {
panel.terminate();
}
}
}
Et voici l'activité principale:
public class MainActivity extends AppCompatActivity {
private PendulumViewPager pager;
private ArrayList<SurfacePanelFragment> fragments = new ArrayList<SurfacePanelFragment>(2);
private ImageButton stopButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayShowTitleEnabled(false);
pager = findViewById(R.id.view_pager);
pager.setAdapter(new FragmentStatePagerAdapter(getSupportFragmentManager()) {
@Override
public Fragment getItem(int position) {
SurfacePanelFragment frag = new SurfacePanelFragment();
switch (position) {
case 0:
frag.setType(SurfacePanel.SINGLE_PENDULUM);
fragments.add(0, frag);
return frag;
case 1:
frag.setType(SurfacePanel.DOUBLE_PENDULUM);
fragments.add(1, frag);
return frag;
default:
return null;
}
}
@Override
public int getCount() {
return 2;
}
@Override
public CharSequence getPageTitle(int position) {
switch (position){
case 0: return "Single";
case 1: return "Double";
default: return "";
}
}
});
TabLayout pagerTabs = findViewById(R.id.pager_tabs);
pagerTabs.setTabGravity(TabLayout.GRAVITY_FILL);
pagerTabs.setupWithViewPager(pager);
stopButton = findViewById(R.id.stop_button);
stopButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
startStopCurrentPendulum((ImageButton) view);
}
});
ImageButton helpButton = findViewById(R.id.help_button);
helpButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
startHelpActivity();
}
});
}
private void startStopCurrentPendulum(ImageButton view) {
fragments.get(pager.getCurrentItem()).startStopPendulum(view);
}
public ImageButton getStopButton(){
return stopButton;
}
private void startHelpActivity(){
Intent intent = new Intent(this, HelpActivity.class);
startActivity(intent);
}
Voici la classe SurfacePanel
public class SurfacePanel extends SurfaceView implements SurfaceHolder.Callback {
public static final int SINGLE_PENDULUM = 1;
public static final int DOUBLE_PENDULUM = 2;
private int TYPE = 1;
private PendulumThread _thread;
private boolean needToStartThread = false;
private SurfaceHolder holder;
public SurfacePanel(Context context, AttributeSet attrSet) {
super(context, attrSet);
SurfaceHolder holder = getHolder();
holder.addCallback(this);
}
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
Log.i("WP", String.valueOf(this.getHeight()));
this.holder = surfaceHolder;
if(needToStartThread){
startThread();
needToStartThread = false;
}
}
@Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
}
@Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
if(_thread != null) {
try {
_thread.terminate();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.holder = null;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (_thread != null) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
_thread.click(event);
} else if (event.getAction() == MotionEvent.ACTION_MOVE) {
_thread.updatePos(event);
} else if (event.getAction() == MotionEvent.ACTION_UP) {
_thread.unclick();
}
}
return true;
}
public void startStop(ImageView button) {
if(_thread != null){
if(_thread.isPRunning()){
button.setImageDrawable(getContext().getResources().getDrawable(R.drawable.ic_play_arrow_white_48dp));
_thread.pStop();
}else{
button.setImageDrawable(getContext().getResources().getDrawable(R.drawable.ic_pause_white_48dp));
_thread.pStart();
}
}
}
public void start(){
if(_thread != null){
_thread.pStart();
}
}
public void stop(){
if(_thread != null){
_thread.pStop();
}
}
public void stopRendering(){
if(_thread != null){
Log.i("WP", "A");
_thread.stopRendering();
}
}
public void startRendering(){
if(_thread != null){
Log.i("WP", "D");
_thread.startRendering();
}
}
public void terminate(){
if(_thread != null){
try {
_thread.terminate();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void startThread(){
if(_thread == null || !_thread.isAlive()) {
switch (TYPE) {
case SurfacePanel.SINGLE_PENDULUM:
_thread = new SinglePendulumThread(holder, getWidth(), getHeight(), getContext());
_thread.pStart();
_thread.start();
break;
case SurfacePanel.DOUBLE_PENDULUM:
_thread = new DoublePendulumThread(holder, getWidth(), getHeight(), getContext());
_thread.pStart();
_thread.start();
break;
default:
_thread = new SinglePendulumThread(holder, getWidth(), getHeight(), getContext());
_thread.pStart();
_thread.start();
break;
}
}
}
public void delayStartThread(){
if(holder == null) {
needToStartThread = true;
}else{
startThread();
}
}
public void setType(int type){
TYPE = type;
}
Et voici le fragment de panneau de surface avec la vue du panneau de surface
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<com.astarphysics.wikidpendulum.SurfacePanel
android:id="@+id/canvas"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:layout_editor_absoluteX="8dp"
tools:layout_editor_absoluteY="8dp" />
</RelativeLayout>
C'est le seul fil de pendule
public class SinglePendulumThread extends PendulumThread{
private SurfaceHolder holder;
private Paint paint;
private int backgroundColor;
private int width;
private Context context;
private boolean clicked = false;
private static final double g = 9.81;
private final int RADIUS;
private int length;
private double theta = Math.PI/8;
private double thetaV = 0;
SinglePendulumThread(SurfaceHolder holder, int width, int height, Context context){
this.holder = holder;
this.context = context;
int bobColor = context.getResources().getColor(R.color.colorBob);
int shadowColor = context.getResources().getColor(R.color.shadowColor);
backgroundColor = context.getResources().getColor(R.color.backgroundColor);
paint = new Paint();
paint.setColor(bobColor);
paint.setShadowLayer(5, -1, 2, shadowColor);
this.width = width;
RADIUS = dpToPx(20);
length = dpToPx(200);
}
protected void update(){
if(pRunning && !clicked) {
thetaV += (-1 * g * Math.sin(theta))/length;
theta += thetaV * (40 * Math.pow(10, -2));
}
}
protected void render(){
Canvas canvas = holder.lockCanvas();
canvas.drawColor(backgroundColor);
canvas.drawLine(width/2, 0, (float) ((width/2) + (length * Math.sin(theta))), (float) (length * Math.cos(theta)), paint);
canvas.drawCircle((int) Math.round((width/2) + (length * Math.sin(theta))), (int) Math.round(length * Math.cos(theta)), RADIUS, paint);
holder.unlockCanvasAndPost(canvas);
}
@Override
void click(MotionEvent e) {
clicked = true;
updatePos(e);
}
@Override
void updatePos(MotionEvent e){
length = (int)Math.round(Math.sqrt((Math.abs(e.getX()-(width/2))*Math.abs(e.getX()-(width/2)))+(e.getY()*e.getY())));
theta = Integer.signum(Math.round((e.getX()-(width/2))))*Math.asin((Math.abs(e.getX()-(width/2))/length));
}
@Override
void unclick() {
this.resetForPStart();
clicked = false;
}
private void resetForPStart(){
thetaV = 0;
}
private int dpToPx(int dp) {
DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
return Math.round(dp * (displayMetrics.xdpi/DisplayMetrics.DENSITY_DEFAULT));
}
et c'est le fil double pendule:
public class DoublePendulumThread extends PendulumThread {
private SurfaceHolder holder;
private Paint paint;
private int backgroundColor;
private int width;
private int height;
private Context context;
private boolean clicked1 = false;
private boolean clicked2 = false;
private final int RADIUS;
private final double m1 = 3;
private final double m2 = 3;
private static final double g = 9.81;
private double l1;
private double l2;
private double[] state = new double[4];
private double[] dydt = new double[4];
private double[] prev = new double[4];
private double[] midpt = new double[4];
private static final double h = 0.5;
private static final double DIMENSION = 4;
private static final double HALF = h/2;
private static final double THIRD = h/3;
private static final double SIXTH = h/6;
DoublePendulumThread(SurfaceHolder holder, int width, int height, Context context){
this.holder = holder;
this.context = context;
this.width = width;
this.height = height;
//Setting sizes that require Context to be set
RADIUS = dpToPx(20);
l1 = dpToPx(150);
l2 = dpToPx(150);
state[0] = Math.PI/8;
//Setting up paints for rendering on Canvas
int bobColor = context.getResources().getColor(R.color.colorBob);
int shadowColor = context.getResources().getColor(R.color.shadowColor);
backgroundColor = context.getResources().getColor(R.color.backgroundColor);
paint = new Paint();
paint.setColor(bobColor);
paint.setShadowLayer(5, -1, 2, shadowColor);
}
/*
Evaluates derivatives for Runge-Kutta.
*/
private void loadDys(double[] y){
dydt[0] = y[2]; //Theta1
dydt[1] = y[3]; //Theta2
dydt[2] = (-1*g*(2*m1 + m2)*sin(y[0]) - m2*g*sin(y[0] - 2*y[1]) - 2*sin(y[0] - y[1])*m2*(y[3]*y[3]*l2 + y[2]*y[2]*l1*cos(y[0] - y[1])))/(l1*(2*m1 + m2 - m2*cos(2*y[0]-2*y[1])));
dydt[3] = (2*sin(y[0] - y[1])*(y[2]*y[2]*l1*(m1+m2) + g*(m1+m2)*cos(y[0]) + y[3]*y[3]*l2*m2*cos(y[0]-y[1])))/(l2*(2*m1 + m2 - m2*cos(2*y[0]-2*y[1])));
}
/*
Each time update is run one iteration of the Runge-Kutta method takes place, with time step h.
*/
protected void update(){
if(pRunning && !clicked1 && !clicked2) {
for (int i = 0; i < DIMENSION; i++) {
midpt[i] = state[i];
prev[i] = state[i];
}
loadDys(midpt);
for (int i = 0; i < DIMENSION; i++) {
state[i] += SIXTH * dydt[i];
midpt[i] = prev[i] + HALF * dydt[i];
}
loadDys(midpt);
for (int i = 0; i < DIMENSION; i++) {
state[i] += THIRD * dydt[i];
midpt[i] = prev[i] + HALF * dydt[i];
}
loadDys(midpt);
for (int i = 0; i < DIMENSION; i++) {
state[i] += THIRD * dydt[i];
midpt[i] = prev[i] + h * dydt[i];
}
loadDys(midpt);
for (int i = 0; i < DIMENSION; i++) {
state[i] += SIXTH * dydt[i];
}
}else if(pRunning && clicked1) {
state[3] += (-1 * g * Math.sin(state[1]))/l2;
state[3] = state[3] * 0.9;
state[1] += state[3] * (40 * Math.pow(10, -2));
}
}
protected void render(){
Canvas canvas = holder.lockCanvas();
canvas.drawColor(backgroundColor);
canvas.drawLine(width/2, height/4, (float) ((width/2) + (l1 * Math.sin(state[0]))), (float) (height/4 + l1 * Math.cos(state[0])), paint);
canvas.drawLine((float) ((width/2) + (l1 * Math.sin(state[0]))), (float) (height/4 + l1 * Math.cos(state[0])), (float) ((width/2) + (l1 * Math.sin(state[0])) + (l2 * Math.sin(state[1]))), (float) (height/4 + l1 * Math.cos(state[0]) + l2 * Math.cos(state[1])), paint);
canvas.drawCircle((float) ((width/2) + (l1 * Math.sin(state[0]))), (float) (height/4 + l1 * Math.cos(state[0])), RADIUS, paint);
canvas.drawCircle((float) ((width/2) + (l1 * Math.sin(state[0])) + (l2 * Math.sin(state[1]))), (float) (height/4 + l1 * Math.cos(state[0]) + l2 * Math.cos(state[1])), RADIUS, paint);
holder.unlockCanvasAndPost(canvas);
}
void updatePos(MotionEvent e){
if(clicked1){
l1 = (int)Math.round(Math.sqrt(((e.getX()-(width/2))*(e.getX()-(width/2)))+((e.getY()-height/4)*(e.getY()-height/4))));
if(e.getY() - height/4 < 0) {
if (Math.round(e.getX() - width/2) == 0) {
state[0] = Math.PI;
} else {
state[0] = Integer.signum(Math.round((e.getX() - (width/2)))) * Math.acos((Math.abs(e.getX() - (width/2))/l1)) + Integer.signum(Math.round((e.getX() - (width/2)))) * Math.PI/2;
}
}else if(Math.round(e.getY() - (height/4)) == 0){
state[0] = Integer.signum(Math.round(e.getX() - (width/2))) * Math.PI/2;
}else{
state[0] = Math.asin((e.getX()-(width/2))/l1);
}
}else if(clicked2){
l2 = (int)Math.round(Math.sqrt(((e.getX()-((width/2) + (l1 * Math.sin(state[0]))))*(e.getX()-((width/2) + (l1 * Math.sin(state[0])))))+((e.getY()-(height/4 + l1 * Math.cos(state[0])))*(e.getY()-(height/4 + l1 * Math.cos(state[0]))))));
if(e.getY() - (height/4 + l1 * Math.cos(state[0])) < 0){
if(Math.round(e.getX() - ((width/2) + l1*sin(state[0]))) == 0){
state[1] = Math.PI;
}else {
state[1] = Integer.signum((int) Math.round((e.getX() - ((width/2) + (l1 * Math.sin(state[0])))))) * Math.acos((Math.abs(e.getX() - ((width/2) + (l1 * Math.sin(state[0]))))/l2)) + Integer.signum((int) Math.round((e.getX() - ((width/2) + (l1 * Math.sin(state[0])))))) * Math.PI/2;
}
}else if(Math.round(e.getY() - (height/4 + l1 * Math.cos(state[0]))) == 0) {
state[1] = Integer.signum((int) Math.round(e.getX() - ((width/2) + l1*sin(state[0])))) * Math.PI/2;
}else{
state[1] = Math.asin((e.getX()-((width/2) + (l1 * Math.sin(state[0]))))/l2);
}
}
}
void click(MotionEvent e){
if((e.getX() - ((width/2) + (l1 * Math.sin(state[0])) + (l2 * Math.sin(state[1]))))*(e.getX() - ((width/2) + (l1 * Math.sin(state[0])) + (l2 * Math.sin(state[1])))) + (e.getY() - (height/4 + l1 * Math.cos(state[0]) + l2 * Math.cos(state[1])))*(e.getY() - (height/4 + l1 * Math.cos(state[0]) + l2 * Math.cos(state[1]))) <= RADIUS*RADIUS){
clicked2 = true;
}else {
clicked1 = true;
}
updatePos(e);
}
void unclick(){
if(clicked1 || clicked2) {
state[2] = 0;
state[3] = 0;
for (int i = 0; i < DIMENSION; i++) {
dydt[i] = 0;
midpt[i] = 0;
prev[i] = 0;
}
clicked1 = false;
clicked2 = false;
}
}
private int dpToPx(int dp) {
DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
return Math.round(dp * (displayMetrics.xdpi/DisplayMetrics.DENSITY_DEFAULT));
}
private static double sin(double x){
return Math.sin(x);
}
private static double cos(double x){
return Math.cos(x);
}
Voici l'activité principale dans laquelle le fragment est intégré dans le pager de vue.
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout 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.astarphysics.wikidpendulum.MainActivity"
>
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<com.astarphysics.wikidpendulum.PendulumViewPager
android:id="@+id/view_pager"
android:layout_width="0dp"
android:layout_height="0dp"
tools:layout_constraintTop_creator="1"
tools:layout_constraintRight_creator="1"
tools:layout_constraintBottom_creator="1"
android:layout_marginStart="8dp"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginEnd="8dp"
app:layout_constraintRight_toRightOf="parent"
android:layout_marginTop="8dp"
tools:layout_constraintLeft_creator="1"
android:layout_marginBottom="8dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp">
</com.astarphysics.wikidpendulum.PendulumViewPager>
</android.support.constraint.ConstraintLayout>
<android.support.design.widget.AppBarLayout
android:layout_height="wrap_content"
android:layout_width="match_parent">
<android.support.v7.widget.Toolbar
app:layout_scrollFlags="enterAlways"
android:id="@+id/toolbar"
android:layout_height="192dp"
android:layout_width="match_parent"
app:contentInsetLeft="0dp"
app:contentInsetStart="0dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="144dp">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:padding="10dp">
<android.support.v7.widget.AppCompatImageButton
android:id="@+id/stop_button"
android:layout_width="48dp"
android:layout_height="48dp"
app:srcCompat="@drawable/ic_pause_white_48dp"
android:background="?attr/selectableItemBackgroundBorderless"
android:layout_marginRight="10dp"
android:layout_marginEnd="10dp"/>
<android.support.v7.widget.AppCompatImageButton
android:id="@+id/help_button"
android:layout_width="48dp"
android:layout_height="48dp"
app:srcCompat="@drawable/ic_help_white_48dp"
android:background="?attr/selectableItemBackgroundBorderless" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:layout_width="80dp"
android:layout_height="80dp"
android:src="@drawable/icon"/>
<TextView
android:layout_width="150dp"
android:layout_height="wrap_content"
android:text="@string/app_name"
android:gravity="center"
android:textSize="24sp"
android:fontFamily="sans-serif-smallcaps"
android:textColor="@color/textColor"/>
</LinearLayout>
</RelativeLayout>
<android.support.design.widget.TabLayout
android:id="@+id/pager_tabs"
android:layout_width="match_parent"
android:layout_height="48dp">
</android.support.design.widget.TabLayout>
</LinearLayout>
</android.support.v7.widget.Toolbar>
</android.support.design.widget.AppBarLayout>
</android.support.design.widget.CoordinatorLayout>
Si vous pensez qu'il ya quelque chose d'autre, alors je peux ajouter le code.
Merci.
L'image unique pendule semble avoir une sorte de canevas sur la zone sombre. Dans l'image à double pendule, ce canevas ne couvre que la moitié de la zone sombre. Quelle est cette zone couverte par le canevas? L'écrasement peut être lié à l'écrasement de cette zone de canevas. Utilisez l'inspecteur de disposition dans Android Studio pour voir ces deux images. Vous pouvez également envoyer du code/XML qui traite de cette zone. – Cheticamp
Merci pour la réponse. La page entière est une vue de surface, le pendule est libre de prendre la moitié inférieure de l'écran dans l'exemple unique, il est juste dans les images qu'il n'a pas. Je ne suis pas sûr de ce que vous voulez dire par le fait qu'il y ait un canevas. –
À propos du canevas: Regardez l'image à deux pendules. La moitié supérieure de la zone sombre avec le pendule a un aspect plus léger et dépoli. La moitié inférieure est beaucoup plus sombre. Avec le pendule unique, tout est noir et de la même couleur. C'est ce que je remets en question. Postez votre classe 'SurfacePanel' et le code XML associé. – Cheticamp