Custom game or draw loop within XML View - java

I've developed apps and games in the past. Now I'm doing one which is a mixture (don't ask..)
Anyhow I was wondering if was possible to draw a custom loop within the view, example.
I want to do this so achieve complete control loops. Maybe a master loop on top of the view's that's always running (If that's possible).
Relative Layout
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:paddingLeft="16dp"
android:paddingRight="16dp"
/>
Within the layout would it be possible to implement a loop as such (obviously in another thread with a bit more code for checking etc etc)
Canvas draw loop
RectF CustomViewWidthAndHeight = new RectF(); //Set using view ID.
do
{
//Using circle as an example.
canvas.drawCircle(Blag, XY);
XY++; //An example.
}
while(endLoopSometime)
How would one go about implementing this if it's wise too, or advising me of another method.

It sounds like you are trying to build your own Custom View. The Android team has been improving the documentation on the Android Developer website. There is a tutorial in the training section on Creating Custom Views which should get you started.

Related

Can I use ScrollView instead of Container View?

export default class Video extends Component {
render() {
return (
<ScrollView style={styles.container}>
<ImageBackground source={require('../asset/Video-Img.jpg')}
style={styles.bgImg}>
<MaterialIcon name="play-circle-outline" size={55} color={'#fff'} />
</ImageBackground>
This is how i execute my code instead of Container View. Any problem will happen with this?
Just a suggestion but if developing for iOS, I would wrap the entire ScrollView within SafeAreaView.
<SafeAreaView>
<ScrollView style={styles.container}>
<ImageBackground source={require('../asset/Video-Img.jpg')}
style={styles.bgImg}>
<MaterialIcon name="play-circle-outline" size={55} color=
{'#fff'} />
</ImageBackground>
</ScrollView>
</SafeAreaView>
Why?
The purpose of SafeAreaView is to render content within the safe area
boundaries of a device. It is currently only applicable to iOS devices
with iOS version 11 or later.
But ScrollView as you have is perfectly fine to do so. Just be sure to read up on the documentation - especially the part in the first paragraph relating to the height.
Also, depending on how much content you are displaying - it may have an impact on performance.
ScrollView renders all its react child components at once, but this
has a performance downside.
If you are looking to just list items, consider FlatList.
This is where FlatList comes into play. FlatList renders items lazily,
when they are about to appear, and removes items that scroll way off
screen to save memory and processing time.
FlatList is also handy if you want to render separators between your
items, multiple columns, infinite scroll loading, or any number of
other features it supports out of the box.
Yes you can use scrollview instead of view

Add Custom Control as Marker OSMDROID BONUS PACK

Can I add Custom Control as Marker to OSMBONUSPACK?
I create some Buttons and image in Android xml file Named MyMarkerItem.xml
I would like something like MyMarker.setDesign(R.layout.MyMarkerItem);
Thanks
OK, I understand that you want the marker icon itself to be not a simple bitmap, but a layout.
What you can do is to use the marker infowindow "instead" of the marker icon.
First of all, create a new class CustomInfoWindow which inherits from MarkerInfoWindow - the default InfoWindow for Markers, and uses your own layout:
public class CustomInfoWindow extends MarkerInfoWindow {
public CustomInfoWindow(MapView mapView) {
super(my_own_layout, mapView);
}
}
CustomInfoWindow myCustomInfoWindow = new CustomInfoWindow(mapView);
Then, just after creating your Marker, do that:
Set a marker icon as a 1x1 pixel size bitmap, fully transparent: setIcon(mySmall_InvisibleIcon)
Set the marker infowindow to your own: setInfoWindow(myCustomInfoWindow)
Set the infowindow "anchor" to the most appropriate and natural position, depending on the "look" of your layout: setInfoWindowAnchor(ANCHOR_CENTER, ANCHOR_CENTER) maybe?
Force the opening of the infowindow: showInfoWindow()
All these steps are fairly simple.
But then, I guess you expect some behaviour to happen when the user will click on your layout buttons.
So, inside your CustomInfoWindow code, you will certainly have to do some work => follow this tutorial.
Markers in Osmdroid arent actually android views and therefore it's not possible to add other components into them. They are basically just an image.
Simple and suggested solution
You can add your components to a MarkerInfoWindow which is displayed after a click, though.
marker.setInfoWindow(new MarkerInfoWindow(R.layout.MyMarkerItem, mapView));
Possible "real" soluiton
If you really need such behaviour - meaning you really need multiple buttons displayed on a map as a "marker" and give the user the opportunity to click on them - it should be possible to create your own implementation of a Marker-like class. In other words, you would have to implement your own subclass of OverlayWithIW or Overlay and override (mainly) the draw method (which should draw your buttons to a canvas) and the onSingleTapConfirmed method, where you would need to detect properly on which button user clicked and call the related action. Try to go through source of the Marker class, it's a good example.
But keep in mind: this is an advanced task. Everything related to drawing on canvas can lead to performance issues if it's not done properly. There will be edge cases you'll have to cover. There may be other problems you'll need to solve and debug. I would not suggest such a solution to a beginner.
It's August 2021 and I wanted to add an arbitrary layout as my marker item. Much as the OP is asking for here.
I tried the Simple and suggested solution of https://stackoverflow.com/a/53003664/866333:
marker.setInfoWindow(new MarkerInfoWindow(R.layout.MyMarkerItem, mapView));
I get a runtime exception when I click it:
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.TextView.setText(java.lang.CharSequence)' on a null object reference.
I refine my layout down to a single TextView widget for arguments sake and the error persists.
I give up on that answer and attempt the accepted one: https://stackoverflow.com/a/53216542/866333
public class CustomInfoWindow extends MarkerInfoWindow {
public CustomInfoWindow(MapView mapView) {
super(my_own_layout, mapView);
}
}
CustomInfoWindow myCustomInfoWindow = new CustomInfoWindow(mapView);
Using the same my_own_layout as before, let's call it R.layout.my_info_window
I get the same error:
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.TextView.setText(java.lang.CharSequence)' on a null object reference
I dug into the AS-reverse engineered (thanks AS) source code to discover the reason for this error is that the layout being passed to the MarkerInfoWindow super class constructor has particular id requirements.
We must have these ids in our layout: bubble_title, bubble_description, bubble_subdescription, bubble_image
Here is a minimal working example:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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">
<TextView
android:id="#+id/bubble_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView"
tools:layout_editor_absoluteX="153dp"
tools:layout_editor_absoluteY="20dp" />
<TextView
android:id="#+id/bubble_description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView"
tools:layout_editor_absoluteX="153dp"
tools:layout_editor_absoluteY="39dp" />
<TextView
android:id="#+id/bubble_subdescription"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView"
tools:layout_editor_absoluteX="153dp"
tools:layout_editor_absoluteY="58dp" />
<ImageView
android:id="#+id/bubble_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:srcCompat="#drawable/marker_cluster"
tools:layout_editor_absoluteX="145dp"
tools:layout_editor_absoluteY="76dp" />
</androidx.constraintlayout.widget.ConstraintLayout>
That works great!
I can even attempt to customise by appending another widget:
<TextView
android:id="#+id/anothertexttestview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="look ma!"
tools:layout_editor_absoluteX="153dp"
tools:layout_editor_absoluteY="125dp" />
The absoluteY is ignored and superimposed on the only text I set programmatically, the title. IOW, the widget isn't purely declarative xml. I'm afraid ConstraintLayout is after my time as a front end engineer so I'll leave it to the reader to experiment from here.

Android/Java - Combinding custom SurfaceView and XML Layout?

I am making a simple game as a project that is basically a simple version of Galaga with some modifications. I am very new to android and Java (primarily a C++ person) so at first I just made the ship automatically move right and holding down on the screen makes the ship move left. I did this to keep it simple (as it was easy to implement an on-touch listener within my GameView for this task) so that I could finish the rest of the basic framework of the app before going back and improving the functionality of particular bits.
Right now my GameView is created programmatically within GameActivity and then "setContentView()" is used to set the activity's view to the new GameView:
public class GameActivity extends AppCompatActivity {
private GameView gameView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
gameView = new GameView(this, size.x, size.y);
setContentView(gameView);
}
Now what I want, is two small buttons in the corner of the screen that move the ship left and right, but I am stuck on how to easily do this because each way I keep thinking of gets really complicated (mostly due to being an android novice).
The two best ways I can think of are as follows:
1) Use the Android Studio XML design tool to place the buttons and my custom SurfaceView (GameView) into the proper locations and then just use "setContentView(R.layout.activity_game)" within my GameActivity.
This would be great; however, there's two problems I cannot figure out how to overcome. First, when I drag "view" into the layout for GameActivity and select my custom SurfaceView "GameView" in the pop-up window, I get an error:
and additionally, as you can see in the code I posted, a GameView needs to be passed two integers whenever it is created and I don't see how I could make this happen if I just put a GameView in my XML layout with the designer.
2) Continue creating the GameView programmatically like I am, setup the GameActivity layout using the designer to contain all the buttons I need, then programmatically add the GameView (custom SurfaceView) to the GameActivity layout before finally using "setContentView(R.layout.activity_game)". This seems the most simple to me, but I don't know how to grab a reference to the entire XML layout that's created with the activity by default (activity_game.xml) and then add the created GameView to it. I can only find code examples for using "findViewById()" to reference pieces of an XML made layout (like a button, or linear layout within the XML made layout). I imagine I might be able to create a Frame layout or something similar within the XML designer and then attach everything to that and use "findViewById()" to attach my GameView to the frame, but I don't know if that would work. Finally, I have a feeling that because the buttons on the XML layout would have existed first, programmatically adding the GameView would mean that the buttons would get covered up and I don't know how to avoid that.
Sorry for the long-winded question but I just couldn't find any sample code or previous questions/answers that addressed this specifically, I could only find bits and pieces that I wasn't sure how to put together.
Any help on the easiest way to have my buttons created in "activity_game.xml" appear on-top of my programmatically created GameView so I can easily position the buttons and easily grab them by ID for on-click listeners?
EDIT:
As requested this is the current setup for activity_game.xml, the frame layout is just there as part of my experimentation but is not actually being used right now since the content view for the activity is set to GameView. I have the button just floating there because right now I am just trying to get it to show up and will worry about proper implementation once I reach that point:
<?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:id="#+id/activity_game"
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.chrisheimlich.galaticrenegade.GameActivity">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/testFrame"
android:layout_alignParentStart="true">
<Button
android:text="Button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignParentStart="true"
android:layout_marginStart="113dp"
android:layout_marginTop="14dp"
android:id="#+id/button2" />
</FrameLayout>

Animated Views move outside of my layout

I have a ScrollView which contains several RelativeLayouts and LinearLayouts like this:
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/scroll"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true" >
<RelativeLayout >
</RelativeLayout>
<LinearLayout >
</LinearLayout>
</ScrollView>
Now, when I click on one of those layouts, I want it to expand and reveal more information. I have managed to do this by scaling the layout I want vertically with a PropertyAnimator:
relativeLayout.animate().scaleY(100).setDuration(duration).start();
At the same time, I use another PropertyAnimator to move any Views below the one I expanded vertically so that there's enough space for the expanded layout. So far it is working.
Unfortunately, the Views that move somehow end up outside of the viewport of the ScrollView, so I'm unable to scroll down and see the information in those Views. Essentially, the vertical translation of those views renders their lower part unreachable, since the viewport does not expand too.
I have set android:fillViewPort="true" on the ScrollView. And I have also tried to do it programmatically with setFillViewPort() but neither has had any effect.
What's wrong? Why is it not working?
When you perform translation animations on Views then those Views don't really move inside the layout. Its just visual for the User, but when it comes to layouting and/or measuring than any translation values are ignored. It is always as if the Views are not translated at all.
What I am guessing you are doing right now is this:
You react to the click event and expand the View you want to expand.
You calculate how much the other Views need to move to accommodate the expanded View.
Then you perform translate animations on those Views by much they need to move.
And then as a result suddenly a few Views move off screen.
This approach can actually never work. You always need to remember that a Views position in the layout is determined just by the layout. All your translations are essentially just for show. So this is what's actually happening when you try to do the above:
You react the to the click event and expand the View.
This expansion causes Android to start a layouting and measuring process. The positions and sizes of all Views is calculated and they are positioned at their new location with their new size.
Since now the Views are already at the location they are going to be after the expansion you translation animation just moves the Views further down, beyond the point they are supposed to be.
As a side effect of this the Views seem to move off screen for no apparent reason.
So what can you do about this? Essentially you need to tackle this problem the other way around. As I mentioned above Android already calculates the new sizes and positions of all Views for you, and you can use that to your advantage.
There are two basic solutions for your problem. Either you let Android perform the animations for you with LayoutTransitions or you perform your animations manually. Both ways use something called the ViewTreeObserver. It can be used to listen for changes in the layout or new drawing processes.
But first and foremost: ScrollView is supposed to work with only one child. So to prevent any future bugs or problems put all your items in the ScrollView inside of another LinearLayout with vertical orientation.
1) Using LayoutTransition
This would only work from API Level 16 and above. Below API Level 16 visibility animations and translation animations would be handled automatically, but to get height changes animated you need to have API level 16.
One important thing I have to mention is that:
LayoutTransition animates changes for you. So you can remove all you custom animations if you use it. If you leave your own animations in you are just going to create conflicts with the animations performed by LayoutTransition.
If you don't like the animations performed by LayoutTransition you can customise them! I will explain how to do that further down below.
I usually use a helper method like this to setup a LayoutTransition.
public static void animateLayoutChanges(ViewGroup container) {
final LayoutTransition transition = new LayoutTransition();
transition.setDuration(300);
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
transition.enableTransitionType(LayoutTransition.CHANGING);
transition.enableTransitionType(LayoutTransition.APPEARING);
transition.enableTransitionType(LayoutTransition.CHANGE_APPEARING);
transition.enableTransitionType(LayoutTransition.DISAPPEARING);
transition.enableTransitionType(LayoutTransition.CHANGE_DISAPPEARING);
}
container.setLayoutTransition(transition);
}
This will enable all possible automatic transitions on API Level 16 and above and just use the by default enabled transitions below that. Just use it like this:
AnimatorUtils.animateLayoutChanges(linearLayout);
If you call this method on the LinearLayout in your ScrollView then all changes to height/width/visibility of the LinearLayout and its direct children will be animated for you. Also item add/remove animations are taken care of for you.
To enable all kinds of transitions like resize animations you need to set the LayoutTransitions in code, but you can enable basic transitions like item add/remove animations by setting the property
android:animateLayoutChanges="true"
on a ViewGroup in your xml layout.
There exists only minimal documentation on LayoutTransitions, but the basics are covered here.
If you want you can customise the animations for each event like adding/removing a View or changing something about the View like this:
// APPEARING handles items being added to the ViewGroup
transition.setAnimator(LayoutTransition.APPEARING, someAnimator);
// CHANGING handles among other things height or width changes of items in the ViewGroup
transition.setAnimator(LayoutTransition.CHANGING, someOtherAnimator);
Here is a DevByte video which explains LayoutTransitions in greater detail:
LayoutTransitions enable easy fade/move/resize animations
Also note that container views can essentially cut off parts of the animations when the height of a parent changes. This won't happen in your case since your ScrollView has a fixed size and does not resize based on the children inside the ScrollView, but if you implement something like this in a ViewGroup with wrap_content then you need to set android:clipChildren="false" on all containers above the Views you are trying to animate. You can alternatively also use setClipChildren() in code.
2) Animating all items manually.
This is a much more difficult than using LayoutTransitions, mainly because you have to know a lot about the layouting and measuring process, otherwise you are going to cause problems. Nevertheless once you get the hang of it you can perform all kinds of custom animations.
The basic process is like this:
Record current View state.
Change layout to the state after the animations are finished
After Android is done layouting and measuring everything record the new values.
Now animate the Views from their old position to their new one
The core of this process is listening for changes in the view hierarchy. This is done using the ViewTreeObserver. There are multiple possible callbacks you can use, for example OnPreDrawListener or OnGlobalLayoutListener. Generally you would implement them like this:
final Animator animator = setupAnimator();
animator.setTarget(view);
// Record the current state
animator.setupStartValues();
modifyChildrenOfLinearLayout();
linearLayout.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
// Remove the callback immediately we only need to catch it this one time.
linearLayout.getViewTreeObserver().removeOnGlobalLayoutListener(this);
// Record the new state
animator.setupEndValues();
// Start the animation
animator.start();
}
});
OnGlobalLayoutListener is better at catching layout changes since it is called after a layouting process has finished. OnPreDrawListener is called before the next frame is drawn, but their is no guarantee that the layouting process has already finished. But in practice this difference is negligible. Much more important is that on older slower devices there might be a short flash of the layout in its new state because they need some time to process each step. You can prevent that by using an OnPreDrawListener and returning false once. Since OnGlobalLayoutListener is also only completely available on newer API levels you should in most cases use OnPreDrawListener.
If LayoutTransitions does not provide you with an adequate solution to your problem and you have/want to implement the animations manually than learning how to perform animations efficiently is important. You can look at the source code of LayoutTransition here. The implementation of LayoutTransition essentially does exactly what I have been explaining here and it is a best practice implementation. I often find myself looking through the source code of the android.animation package to learn new things about how to animate efficiently and if you want to understand animations on Android I suggest you do the same!
You can also watch a few Android DevBytes videos about animations like this one:
ListView Expanding Cells Animation
In this video he explains how to animate an expanding cell in ListView by using an OnPreDrawListener.
Just always remember, the Layouting Engine is your friend. Don't try to reinvent the wheel and do stuff manually a layouting process would already do for you. And never call requestLayout() while performing animations!
From Android Developer site :
A ScrollView is a FrameLayout, meaning you should place one child in it containing the entire contents to scroll; this child may itself be a layout manager with a complex hierarchy of objects. A child that is often used is a LinearLayout in a vertical orientation, presenting a vertical array of top-level items that the user can scroll through.
I can see that you have added multiple layouts as child in Scroll View, please add one linear layout and add rest of layout in that LinearLayout.
Hope it will solve your problem
Try this.
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/scroll"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<RelativeLayout >
</RelativeLayout>
<LinearLayout >
</LinearLayout>
</LinearLayout>
</ScrollView>
Scrollview must have only one child to it. So I created only one LinearLayout child and add your rest code in it.
just add android:clipChildren="false"to your parent animated view and animation works outside of view.

GridView: How can I get rid of extra space from my GirdView object?

I'm writing an application for Android phones for Human vs. Human chess play over the internet. I was looking at some tutorials, to learn how to develop Android applications and found a very nice example of making galleries (it was a GridView usage example for making a gallery about dogs) and the idea came to draw the chess table using a GridView, because the example project also handled the point & click event and I intended to use the same event in the same way, but for a different purpose. The game works well (currently it's a hotseat version), however, I'm really frustrated by the fact that whenever I rotate the screen of the phone, my GridView gets hysterical and puts some empty space in my chess table between the columns. I realized that the cause of this is that the GridView's width is the same as its parent's and the GridView tries to fill its parent in with, but there should (and probably is) be a simple solution to get rid of this problem. However, after a full day of researching, I haven't found any clue to help me to make a perfect drawing about my chess table without a negative side effect in functionality.
The chess table looks fine if the phone is in Portrait mode, but in Landscape mode it's far from nice.
This is how I can decide whether we are in Portrait or Landscape mode:
((((MainActivity)mContext).getWindow().getWindowManager().getDefaultDisplay().getWidth()) < ((MainActivity)mContext).getWindow().getWindowManager().getDefaultDisplay().getHeight())
In the main.xml file the GridView is defined in the following way:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<GridView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/gridview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:numColumns="8"
android:verticalSpacing="0dp"
android:horizontalSpacing="0dp"
android:stretchMode="columnWidth"
android:gravity="center"
>
</GridView>
...
</LinearLayout>
I appreciate any help with the problem and thank you for reading this.
Portrait: http://www.freeimagehosting.net/image.php?f388b3ec64.png
Landscape: http://www.freeimagehosting.net/image.php?ee790603a2.png
A GridView probably isn't what you want here. GridView, like ListView, is for efficiently presenting scrolling, unbounded data sets. A chess board is neither. Populating a TableLayout programmatically is probably what you want instead.
The reason your GridLayout doesn't seem to be honoring android:layout_width="wrap_content" is that since GridView is meant for displaying unbounded data where each item can have a different size, it doesn't trust that items have a uniform width that can be reasonably measured. (If an adapter has 10,000 items, should GridView measure all of them to determine the correct column width?)
If you're going to try to keep using GridView for this anyway (which you shouldn't), try setting an explicit value for android:layout_width rather than wrap_content. This will stop the GridView from expanding to fill the available space. You can also use alternate layouts for different screen orientations using the resource system as described here. Alternatively you can disable landscape mode using android:screenOrientation="portrait" on the activity tag in your manifest. ;)
The problem is simply solvable using the setPadding method of your GridView object.

Categories

Resources