NestedScrollView fading/moving views in/out on Scroll Up/Down - java

I have a nested scroll view with child views (wrapped in layout) and I need to fade in/out on scroll up/down.
My issue is trying to get the vertical scroll value reversed (to lessen the alpha value for fading in and out on scroll).
As standard, the ScrollY (vertical Scroll value) increases/starts from
0 as the user scrolls to the bottom of the NestedScroll from the Top
I'm sure there would is a math equation to get the correct value for alpha fading in/out but cant quite stick it but once I do, I could also get values to move views up/down and fade in/out on scroll.
Not wanting to use CoordinatedLayout to collapse etc
NestedScroll View (XML)
<androidx.core.widget.NestedScrollView
android:id="#+id/nested_scroll"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<!-- Fade In/Out -->
<RelativeLayout
android:id="#+id/fade_me_on_scroll"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
</RelativeLayout>
</LinearLayout>
</androidx.core.widget.NestedScrollView>
Fragment with NestedScroll View in onCreateView (Kotlin)
//...
//...
//...
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
//...
//...
//region NestedScroll
myNestedScroll = binding.NestedScroll
if (myNestedScroll != null) {
myNestedScroll.setOnScrollChangeListener(
NestedScrollView.OnScrollChangeListener { v, scrollX, scrollY, oldScrollX, oldScrollY ->
//set Scroll Calculation Factor, use in calculation
var scrollCalculateFactor = 25
//set Scroll min range, if ScrollY has passed this value, do processing in the if statement below
var minScrollRange = 10
//set Scroll max range, if ScrollY has passed this value, stop processing
var maxScrollRange = 250
//if scroll is with range, do processing
if(scrollY in minScrollRange..maxScrollRange) {
//wrap in try block just in case it goes paer shaped ...
try {
//set current ScrollY value to alpha value
//issue is here, works correctly as it returns the alpha value (i.e 0.20f)
//but as user scrolls to the Bottom the value (alpha) increases which fades in views (and as user scroll to the Top, fades out views), but I need the opposite to happen so views fade in/out correctly
var currentCalculatedAlpha = scrollY.toFloat() / maxScrollRange.toFloat()
if (scrollY > oldScrollY) {
//region Scrolling to the Bottom
//fade views out here
//fade the View using alpha setting
//however as the scrollY value increases, the alpha increases, fading in the view, need to opposite to happen
//binding.FadeMeOnScroll.alpha = currentCalculatedAlpha
//endregion Scrolling to the Bottom
} else if (scrollY < oldScrollY) {
//region Scrolling to the Top
//fade views back in
//fade the View using alpha setting
//however as the scrollY value decreases, the alpha decreases, fading out the view, need to opposite to happen
//binding.FadeMeOnScroll.alpha = currentCalculatedAlpha
//endregion Scrolling to the Top
} else if(scrollY >= maxScrollRange){
//region Scrolled passed max range
//stop processing or manually fade out
//fade the View using alpha setting
//binding.FadeMeOnScroll.alpha = 0f
//endregion Scrolled passed max range
}
}catch (exception: Exception) {
//log error
Log.e("exception", "exception: " + exception.message)
}
}
})
}
//endregion NestedScroll
}

Related

how to refresh a RecyclerView draw (not datas)?

In a RecyclerView, I change the presentation for some items as follows:
if (stk.getQty() == 0) { // mise en valeur des stocks à 0 non purgeables
cellStockQty.setTextColor(Color.RED);
GradientDrawable border = new GradientDrawable();
border.setColor(mIV.getResources().getColor(R.color.colorAugment)); // white background
border.setStroke(1, mIV.getResources().getColor(R.color.colorAccent)); // black border with full
mIV.setBackground(border);
}
When I delete an item, I manage to remove it from the display, with notifyItemRemoved(index); but the next item takes the presentation of the item that was deleted.
Of course, if I leave this activity then come back, all is right.
How to make sure to refresh the display, depending on the data?
before deleting Jjjjjj item
after deleting Jjjjjj item
Edit:
Here is my original layout
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="0dp"
android:foreground="#drawable/card_foreground"
app:cardBackgroundColor="#color/stockRecyclerviewBackground"
app:cardCornerRadius="6dp"
app:cardElevation="4dp"
app:cardMaxElevation="6dp"
app:cardPreventCornerOverlap="false"
app:cardUseCompatPadding="true">
<include layout="#layout/recystock_cell_include" />
</androidx.cardview.widget.CardView>
Make sure to clear background mIV.setBackground(null);
in else statement.
Your onBindViewHolder is broken. A properly written onBindViewHolder sets EVERY field of the view that could possibly change. And in a proper RecyclerView implementation, non of the click handlers or other actions ever touch the view itself, they all change the model then notify the adapter an iten has changed. Obviously you're not doing that- you're inheriting some of the styling from the old view. Fix your onBindViewHolder to specify all of the view information.
It seems that just doing:
mStockRecyclerView.setAdapter(mAdapter);
is enough.
Sorry for the noise.
Another solution, found with the help of the answers here and there Reset Button to default background is to reset the background, using setTag() and getTag() like:
if ( mIV.getTag() == null ) mIV.setTag(mIV.getBackground());
if (cellStockQty.getTag() == null ) cellStockQty.setTag(cellStockQty.getCurrentTextColor());
if (stk.getQty() == 0) { // mise en valeur des stocks à 0 non purgeables
cellStockQty.setTextColor(Color.RED);
GradientDrawable border = new GradientDrawable();
border.setColor(mIV.getResources().getColor(R.color.colorAugment)); // white background
border.setStroke(1, mIV.getResources().getColor(R.color.colorAccent)); // black border with full
mIV.setBackground(border);
} else {
cellStockQty.setTextColor((int)cellStockQty.getTag());
mIV.setBackground((Drawable) mIV.getTag());
}

Android divide an image in multiple region for onClick events

In this application, I have for example an image representing the map of Germany. I want to be able to click on one specific state, for example, Bavaria and something should happen (on click function).
I can maybe place a table layout on top of the image filled whit blank images and activate the on click method only on the one covering the states, but this is probably bad coding, and I think will be poorly compatible whit other types of device, tablet or bigger/smaller screen.
Another solution can be to create two image of the map. One with different colors of the states, and another with the desired layout to show. Put the colored one as invisible on top of the second one.
XML :
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/my_frame"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#color/background" >
<ImageView
android:id="#+id/image_areas"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:scaleType="fitCenter"
android:visibility="invisible"
android:src="#drawable/mapcolor" />
<ImageView
android:id="#+id/image"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:scaleType="fitCenter"
android:src="#drawable/mapdisplay"/>
</FrameLayout>
Java :
public boolean onTouch (View v, MotionEvent ev) {
final int action = ev.getAction();
// (1)
final int evX = (int) ev.getX();
final int evY = (int) ev.getY();
switch (action) {
case MotionEvent.ACTION_DOWN :
if (currentResource == R.drawable.mapdisplay) {
}
break;
case MotionEvent.ACTION_UP :
// Switch to a different image, depending on what color was touched.
int touchColor = getHotspotColor (R.id.image_areas, evX, evY);
// Switch to a different image, depending on what color was touched.
ColorTool ct = new ColorTool ();
int tolerance = 25;
nextImage = R.drawable.mapdisplay;
// (3)
if (ct.closeMatch (Color.RED, touchColor, tolerance)) {
// Do the action associated with the RED region
// onClick function here ?
} else {
//...
}
break;
} // end switch
return true;
}
Color Tool :
public class ColorTool {
public boolean closeMatch (int color1, int color2, int tolerance) {
if ((int) Math.abs (Color.red (color1) - Color.red (color2)) > tolerance ) return false;
if ((int) Math.abs (Color.green (color1) - Color.green (color2)) > tolerance ) return false;
if ((int) Math.abs (Color.blue (color1) - Color.blue (color2)) > tolerance ) return false;
return true;
} // end match
} // end class
As expected this is not working for me. Can someone explain to me this method or a good way to have an image "map" with multiple regions to click?
I was thinking of having a 2D matrix having a map of the states. There should be an initial version of the matrix which maps with different numbers for the different region based on their locations. For larger or smaller screen size, the matrix needs to be dynamic and remapped among the pixels. Let us consider the following grid as an example.
--------------
00111122224444
01111222222444
11122222444444
11222244444433
12222444444333
22224444444433
22255444444333
22555554443333
25555555433333
--------------
We can see 5 states here with their respective numbering in the matrix which follows the map. If the screen size doubles, you need to translate the values to have a larger segment and vice versa.
I was thinking of plotting such matrix which can be translated into larger or smaller dimensions based on the screen size. Now you need to set the image of the map as screen background and take an onTouchListener to get the pixel of the area touched to determine which area is being clicked.
This is just to give an idea of how this problem could be solved. I found one similar idea here in the MapChart. Hope that helps!

ObjectAnimator not working properly when view.getX() != 0

I'm using ObjectAnimator to translate a view horizontally to the right edge of the outer view. Both views are children of the same layout, with the second view matching width and height of the parent and enclosing the first view. When my activity starts and ObjectAnimator is called to translate the view, it will only end up at the correct destination when the view starts out at 0.0, 0.0. When start coordinates are 100.00,100.00 , the view ends up 100.00 units past where it's supposed to be.
startX = view.getX();
endX = getRight(layout) - view.getWidth();
Log.i("debugger", "going from x="+startX+" to x="+endX);
translateRight = ObjectAnimator.ofFloat(view, "translationX", startX, endX);
And in the animatorListener
#Override
public void onAnimationEnd(Animator animator) {
Log.i("debugger", "end x = "+view.getX());
}
The method I use to get the X coordinate of the right edge of a view
public int getRight(View view){
return (int)(view.getX()+view.getWidth());
}
Snippet of xml
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:weightSum="100"
android:orientation="horizontal"
android:gravity="center">
<RelativeLayout
android:layout_width="0dp"
android:layout_weight="82"
android:layout_height="match_parent">
<View
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/outerView"
/>
<View
android:layout_height="#dimen/view_width"
android:layout_width="#dimen/view_width"
android:background="#drawable/view"
android:id="#+id/view"
android:layout_toRightOf="#id/obstacle1"
android:layout_below="#id/obstacle1"
/>
<View
android:id="#+id/obstacle1"
android:layout_height="#dimen/view_width"
android:layout_width="#dimen/view_width"
android:background="#drawable/obstacle"
android:layout_alignParentTop="true"
/>
layout
When the view starts off in the upper left hand corner (where obstacle 1 is), the view ends up flush against the inside right wall of the outerView, where it should be. However, when the view has non-zero coordinates, as in the example where it sits below and to the right of obstacle1, it goes past the right edge and sits flush against the outside wall of the outerView. The funny thing is, if the view is placed in the xml at the upper left hand corner, it can move as supposed to no matter where it becomes positioned. When it doesn't start in the corner, everything's jacked from the get-go.
The logs look as follows for when view starts at 0,0:
going from x=0 to x=1080
end x = 1080
The logs look as follows for when view starts at 100, 100:
going from x=100 to x=1080
end x = 1180
Does anyone know why this is happening? Any help would be greatly appreciated.
You are translating the view on the X axe, with start value 100. If the translationX attribute of your view is 0, then the animation will start by instantly translating your view by 100.
You should do something like this :
translateRight = ObjectAnimator.ofFloat(view, "translationX", view.getTranslationX(), endX - startX);

Challenge: Custom Animation of ViewPager. Change height of chosen elements (View fold)

I am currently working on custom animation between switching pages in ViewPager. When I slide to the left, View is moving to the left and from below of it new View is coming to the front. I would like to make the view, that moves to the left (that I dispose) to shrink like on the folowing images:
On the second and third image I didn't picture new View coming to the front, but I think it wasn't necessary. Do you have any idea how can I modify the code? I would like to change height of TableLayout, RelativeLayout and FrameLayout and keep the height of both TextViews. Also I would have to change X-position of the whole View. I am looking forward for your creative answers (code). Below I attach my code for the animation.
import android.view.View;
import android.widget.RelativeLayout;
import android.annotation.SuppressLint;
import android.support.v4.view.ViewPager.PageTransformer;
public class DepthPageTransformer implements PageTransformer {
private static float MIN_SCALE = 0.75f;
#SuppressLint("NewApi")
public void transformPage(View view, float position) {
int pageWidth = view.getWidth();
if (position < -1) { // [-Infinity,-1)
// This page is way off-screen to the left.
view.setAlpha(0);
} else if (position <= 0) { // [-1,0]
// Use the default slide transition when moving to the left page
view.setTranslationX(0);
view.setScaleX(1);
view.setScaleY(1);
//float scaleFactor = (1 - Math.abs(position));
//WHAT TO PUT HERE TO ARCHIVE MY GOAL??
//This is how I can get particular layouts:
// RelativeLayout relativeLayout = (RelativeLayout) view.findViewById(R.id.fragment_object_canvas_RelativeLayout1);
//relativeLayout.setScaleX(scaleFactor);
//relativeLayout.setScaleY(scaleFactor);
} else if (position <= 1) { // (0,1]
// Fade the page out.
view.setAlpha(1 - position);
// Counteract the default slide transition
view.setTranslationX(pageWidth * -position);
//view.setRotation(1 - (position*360));
// Scale the page down (between MIN_SCALE and 1)
float scaleFactor = MIN_SCALE
+ (1 - MIN_SCALE) * (1 - Math.abs(position));
view.setScaleX(scaleFactor);
view.setScaleY(scaleFactor);
} else { // (1,+Infinity]
// This page is way off-screen to the right.
view.setAlpha(0);
}
}
}
UPDATE:
I can manipulate with height of whole View (for now I can do only this) with the following code:
LinearLayout relativeLayout = (LinearLayout) view.findViewById(R.id.fragment_object_canvas_linearLayout1);
relativeLayout.setLayoutParams(new FrameLayout.LayoutParams(relativeLayout.getWidth(), NEW_HEIGHT_HERE)));
However, I am not sure what should I put into NEW_HEIGHT_HERE variable to make it work corectly...
try to work with a position float variable.
Get the height of your layout and...:
relativeLayout.setLayoutParams(....,position*height+height)
You seem pretty insistent on people posting original code, but why reinvent the wheel? This library has a ton of great animations for a ViewPager, including one very similar to what you seem to be requesting.
https://github.com/jfeinstein10/JazzyViewPager
JazzyViewPager -
An easy to use ViewPager that adds an awesome set of custom swiping animations. Just change your ViewPagers to JazzyViewPagers and you're good to go!
public enum TransitionEffect {
Standard,
Tablet,
CubeIn,
CubeOut,
Flip,
Stack,
ZoomIn,
ZoomOut,
RotateUp,
RotateDown,
Accordion
}
You can select your animation by calling
private JazzyViewPager mJazzy;
/* ... */
mJazzy.setTransitionEffect(TransitionEffect.*);

Screen height doesn't match actual screen height

Solved:
As Zoltán wrote I didn't take the statusbar and titlebar into consideration (They're both 25 in height)
I used the following code in my onClickListener method inside my Activity and forwarded the results to my Service class and printed it out there:
Rect rectgle = new Rect();
Window window = getWindow();
window.getDecorView().getWindowVisibleDisplayFrame(rectgle);
int StatusBarHeight = rectgle.top;
int contentViewTop = window.findViewById(Window.ID_ANDROID_CONTENT).getTop();
int TitleBarHeight = contentViewTop - StatusBarHeight;
serviceIntent.putExtra("Titlebarheight", Integer.toString(TitleBarHeight));
serviceIntent.putExtra("Statusbarheight", Integer.toString(StatusBarHeight));
-----------------------------------------------------------------------------------------
I am trying to set the layout height of my ImageView in my main.xml, but when I set the layout_height to 270dp (or px) it fills up the whole screen from top to bottom, but my screen size is actually 320x240 (HTC magic - Android 1.5) - So it SHOULDN'T fill up the screen from top to bottom!
Code inside Activity:
Display display = getWindowManager().getDefaultDisplay();
Log.i("Screen height", Integer.toString(display.getHeight())); // Returns 320
Log.i("Screen width", Integer.toString(display.getWidth())); // Returns 240
Code inside main.xml:
<ImageView
android:id="#+id/bitmapImageView"
android:layout_height="270dp" // Fills up the whole screen from top to bottom
android:layout_width="50dp"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:background="#FFFFFF"
android:src="#drawable/ic_launcher" />
Why is this happening? How can I fix it?
Example when using 270 as layout height:
Example when using 240 as layout height:
The height of the status bar and the title bar of your application seems to be about the same as the width of your ImageView, which is 50px judging from your XML.
So then 50px + 270px = 320px, which is the total height of your screen (including the status and title bar).
See: Screen Resolution of android and
scale-independent pixel
Basically, a dp (display-independent pixel) is not the same size on all displays. At your resolution 1dp =~ .75px
To do a full screen activity see: Fullscreen Activity in Android?
Specifically, set: android:theme="#android:style/Theme.NoTitleBar.Fullscreen" in the android manifest for that activity.

Categories