Giter VIP home page Giter VIP logo

Comments (16)

moagrius avatar moagrius commented on May 21, 2024

Sure, it's just the scroll positions, so the native View methods of getScrollX and getScrollY would do it.

from tileview.

D33pTh0ught avatar D33pTh0ught commented on May 21, 2024

okay, thank you for your quick answer,
however this did only work for me when the view was not scaled.
I managed to set the scale of a TileView to the scale of another , but then the position was not correct anymore:

tileview2.moveTo(tileview1.getScrollX, tileview1.getScrollXY);
tileview2.setScale(tileview1.getScale());

Can you tell me whats wrong with this peace of code?
Thanks in advance.

from tileview.

moagrius avatar moagrius commented on May 21, 2024

Try this:

tileview2.scrollTo(tileview1.getScrollX(), tileview1.getScrollY());
tileview2.setScale(tileview1.getScale());

from tileview.

D33pTh0ught avatar D33pTh0ught commented on May 21, 2024

Thanks, now it works :)

from tileview.

D33pTh0ught avatar D33pTh0ught commented on May 21, 2024

With that working now, i ran into another minor issue:

When I manualy zoom in and scroll to another position in the second view and then change back to the first one (where I again getScroll and setScale to the new values from the second view) the image i get is not sharp.
Only when i move the map a little, then the tiles for the needed level of detail are being loaded.

hope my description is not to confusing ... any ideas what I could do to resolve this problem?

from tileview.

moagrius avatar moagrius commented on May 21, 2024

try calling requestRender on the tileview that has not loaded the tiles.

from tileview.

D33pTh0ught avatar D33pTh0ught commented on May 21, 2024

unfortunately I get the same result with calling requestRender.
It is only sharp when i switch to a view I haven't loaded before, or one where the area i move the view to has been loaded before.

from tileview.

moagrius avatar moagrius commented on May 21, 2024

This actually comes up a lot - I strongly suspect it's a validation issue. First thing to do is try refresh on the instance not loading tiles. Hopefully that works - if not, it's most definitely a validation issue, which is a bear with the Android framework - I've tried to catch any potential validation failure everywhere I can, but as I said it happens a lot. If refresh doesn't work for you, try calling _both_ invalidate and postInvalidate (yes, they should be redundant, but they really aren't) on as many layers as your can when that happens (again, should not be necessary but sometimes is - both should cascade but don't always do so reliably) - maybe start on the tile view itself, but to be sure it's happening you may need to recurse down children as well...

Hopefully refresh will do it and you won't have to get into the validation quagmire - post back and LMK how it goes.

from tileview.

D33pTh0ught avatar D33pTh0ught commented on May 21, 2024

refresh and also invalidating didn't work for me.
but maybe I'm doing it wrong:
I have a Fragment which returns different instances of a class Map that extends TileView.
I get those instances by calling getMap(x) where I first scrollTo and setScale to the position of the Map loaded before and then return it.
In this method(getMap) I tried calling requestRender() refresh() and both invalidate() and postInvalidate() on the Map instance before returning it but that didn't work.
Have i got something wrong("as many layers as your can" "recurse down children")? - because I don't know where else I should call this methods.

from tileview.

moagrius avatar moagrius commented on May 21, 2024

requestRender and refresh are TileView methods, and can only be called by TileView instances, so that's pretty straightforward. They should both be called only when the TileView instance is in a viewable state (added to the display list, etc). They should both be called only from the UI thread (if you're calling either method from an AsyncTask, for example, you'd want to post a Runnable to the UI thread to call either method).

Separate from that, the Android framework tries to save resources by only drawing if the last image on the screen is invalid. If there is no change, there's no sense wasting time and resources drawing the same thing again. In general, it does an OK job of determining what is valid and what is not, but can get confused when doing certain things programmatically, like scrolling - thus they (Android) offers two methods: invalidate and postInvalidate. They do the same thing - they mark the View as being _invalid_ and it should be drawn again the next time the UI does a drawing pass. The only difference between the two methods is that postInvalidate automatically sends the invalidate invocation through the UI thread (otherwise you'd have to do it yourself, using the same post and Runnable technique I described earlier).

In theory, if you invalidate a parent, all it's children get redrawn as well, but in practice calling invalidate on a parent does not always work - sometimes you have to target the child that is responsible for the change in drawing state, and this isn't always obvious. These validation issues have come up a lot, and in general they're tough to track down.

If nothing I've suggested has worked, you can either post the relevant bits of your code, or I can take a look at your project if you have it available for download.

from tileview.

D33pTh0ught avatar D33pTh0ught commented on May 21, 2024

I'll post my code here. The interesting part is probably the MapManager.

I have a Fragment which returns the View instances:

public class MapFragment extends Fragment {
    public static final String ARG_SERVICE_NUMBER = "service_number";
    int i;
    public MapFragment() {
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        i = getArguments().getInt(ARG_SERVICE_NUMBER);
        return MainActivity.maps.getMap(i);
    }

    @Override
    public void onPause() {
        super.onPause();
        MainActivity.maps.clear(i);
    }

    @Override
    public void onResume() {
        super.onResume();
        MainActivity.maps.resume(i);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        ((ViewGroup) MainActivity.maps.getMap(i).getParent()).removeView(MainActivity.maps.getMap(i));
    }
}

The variable maps in the Fragment above is an instance of my MapManager where the synchronisation of the view positions is done. This is also the class where i tried to apply your suggestions.

public class MapsManager {
    private static Map[] map;
    private static int currentFloor;
    private static double[] position;
    private static double scale;

    private static MapsManager instance = new MapsManager();

    public MapsManager() {
    }

    public static MapsManager getInstance(Activity activity) {
        currentFloor = 0;
        position = new double[2];
        map = new Map[4];
        map[0] = new MapLevel0(activity);
        map[0].setPosition(700, 100);
        map[0].setScale(0.3);
        map[1] = new MapLevel1(activity);
        map[2] = new MapLevel2(activity);
        map[3] = new MapLevel3(activity);
        return instance;
    }

    public TileView getMap(int i) {
        position = map[currentFloor].getPosition();
        map[i].setPosition((int) position[0], (int) position[1]);

        scale = map[currentFloor].getScale();
        map[i].setScale(scale);

        currentFloor = i;
        //at this point i tried requestRender() refresh() and both invalidate() and postInvalidate()
        //map[i].refresh();
        return map[i];
    }

    public void clear(int i) {
        map[i].clear();
    }

    public void resume(int i) {
        map[i].resume();
    }
}

And here is the Map class:

public class Map extends TileView {
    public Map(Context context) {
        super(context);
        this.setSize(6103, 3207);
        defineRelativeBounds(42.379676, -71.094919, 42.346550, -71.040280);
        setMarkerAnchorPoints(-0.5f, -1.0f);
        setScaleLimits(0, 2);
        setTransitionsEnabled(false);
    }

    public void frameTo(final double x, final double y) {
        post(new Runnable() {
            @Override
            public void run() {
                moveTo(x, y);
            }
        });
    }

    public double[] getPosition() {
        double[] tmp = { getScrollX(), getScrollY() };
        return tmp;
    }

    public void setPosition(int x, int y) {
        scrollTo(x, y);
    }
}

Any ideas what the problem could be?
Feel free to point out any potential issues.

from tileview.

moagrius avatar moagrius commented on May 21, 2024

The good news is that I think I see where the problem is. The bad news is that I'm not sure how to fix it.

So the TileView determins what tiles need to be rendered by examining a Rect that represents the viewport - it's basically the scroll position + the width or height of the TileView itself: https://github.com/moagrius/TileView/blob/master/src/com/qozix/tileview/TileView.java#L742

If the width and height are 0 (e.g., it's not in the display list), then no tiles will ever intersect.

A view will commonly not have width or height until it is has undergone a layout pass. You'll notice if you make a custom view and Log the width / height in the constructor, it will almost always be 0.

A couple things to try.

First, I'd try to post out of onCreateView:

@Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        i = getArguments().getInt(ARG_SERVICE_NUMBER);
        final TileView map = MainActivity.maps.getMap(i);
        map.post(new Runnable(){
             @Override
             public void run(){
                 map.refresh();
              }
        });
       return map;
    }

If that doesn't work, you can try to de-optimize the onLayout requestRender... Either hack the core of TileView.onLayout and remove the conditional:

protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout( changed, l, t, r, b );
        if ( changed ) {
                updateViewport();
                requestRender();
        }
}    

becomes:

protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout( changed, l, t, r, b );
        updateViewport();
        requestRender();
}    

Or if you don't want to hack the core (e.g., if you're using the jar), do the same thing in your subclass

public class Map extends TileView {
    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout( changed, l, t, r, b );
        requestRender();
    }
    // ...

from tileview.

D33pTh0ught avatar D33pTh0ught commented on May 21, 2024

Thank you very much for your detailed answers.
Even though i have no idea why your solutions did't do the trick, I now got it working by overriding the onLayout method in my Map class like this:

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(true, l, t, r, b);
    }

from tileview.

moagrius avatar moagrius commented on May 21, 2024

Awesome, glad you got it working. FWIW, your version (with the changed variable hardcoded to true) should be identical to the core-hack mentioned above.

As a result, I'm going to remove that conditional check entirely, since it's caused other issues before that I've had to tweak other spots to accommodate - #61

Thanks for your feedback, and your determination to get it working!

from tileview.

D33pTh0ught avatar D33pTh0ught commented on May 21, 2024

Nice, I haven't tried this particular solution of yours since I'm using the jar.
Thanks again for your help!

from tileview.

moagrius avatar moagrius commented on May 21, 2024

NP! And good job getting it to work!

from tileview.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.