Categories
discuss

Inversify.js – Reflect.hasOwnMetadata is not a function

I’m trying out Inversify.js for a Typescript application I’m using. Right now, there is no framework involved, so it’s pure ES2015.

I’m trying to follow along the example in the main page, but I’m being hit with: “Reflect.hasOwnMetadata is not a function” when I try to run it in the browser.

I’m using Webpack as package bundler.

Here is my folder structure:

enter image description here

Here is the main app.ts file:

/// <reference path="../typings/index.d.ts" />
/// <reference path="./domain/abstract/match.interface.ts" />

import kernel from "../inversify/inversify.config.ts";

import {symbols} from "../inversify/symbols.ts";

var ninja = kernel.get<INinja>("INinja");

ninja.fight();
ninja.sneak();

interfaces.d.ts:

interface INinja {
    fight(): string;
    sneak(): string;
}

interface IKatana {
    hit(): string;
}

interface IShuriken {
    throw();
}

inversify.config.ts

/// <reference path="../node_modules/inversify/type_definitions/inversify/inversify.d.ts" />
/// <reference path="../node_modules/reflect-metadata/reflect-metadata.d.ts" />
/// <reference path="inversify.ts" />

import {Kernel} from "inversify"
//import {MatchHub} from "../app/components/Hubs/match/match-hub.component.ts";
//import {symbols} from "./symbols.ts";


import {Ninja, Katana, Shuriken} from "./inversify.ts";


var kernel = new Kernel();
kernel.bind<INinja>("INinja").to(Ninja);
kernel.bind<IKatana>("IKatana").to(Katana);
kernel.bind<IShuriken>("IShuriken").to(Shuriken);


export default kernel;

symbols.ts:

export const symbols = {
    Match : Symbol("Match")
}

tsconfig.json:

{
  "compilerOptions": {
    "noImplicitAny": false,
    "experimentalDecorators": true,
    "emitDecoratorMetadata":  true, 
    "removeComments": true,
    "sourceMap": true,
    "target": "es5"
  },
  "exclude": [
    "node_modules",
    "bower_components",
    "wwwroot"
  ]
}

Webpack.config.js:

module.exports = {
  entry: './app/app.ts',
  output: {
    filename: '../Scripts/app/app.js'
  },
  resolve: {
      extensions: ['', '.Webpack.js', '.web.js', '.ts','.js', '.tsx']
  },
  module: {
    loaders: [
        {
          test: /.ts?$/,
          exclude: /(node_modules|bower_components)/,
          loader: 'ts-loader'
        }
    ]
  },
  watch: true
}

Firefox Console Error:

firefox console error

Webpack output:

enter image description here

When I tried to install Inversify the following warnings popped up:

enter image description here

Is it a bug? Or am I doing something wrong? Thanks!

PS: Tried following the sample files, but I couldn’t understand anything!

I come from ASP.NET MVC 5 with Ninject so I can relate for most of the syntax.

Answer

It seems you will need to include the reflect-metadata package. Try adding an import to it in inversify.config.ts by doing:

import "reflect-metadata";
Categories
discuss

Why does webpack need an empty extension

I’m trying to figure out why webpack requires this empty extension.

Inside resolve.extensions there’s always this kind of configuration:

extensions: ['', '.js', '.jsx']

Why can’t it be just this:

extensions: ['.js', '.jsx']

Answer

From the documentation:

Setting this option will override the default, meaning that webpack will no longer try to resolve modules using the default extensions. If you want modules that were required with their extension (e.g. require('./somefile.ext')) to be properly resolved, you must include an empty string in your array. Similarly, if you want modules that were required without extensions (e.g. require('underscore')) to be resolved to files with “.js” extensions, you must include ".js" in your array.

In other words, if you didn’t include the empty string and required a module as ./foo.js, webpack would look for ./foo.js.js and ./foo.js.jsx instead.

Categories
discuss

nested scrollView doesn’t recognize the toolbar

my project has only one toolbar that surrounded by AppBarLayout and also a NestedScrollView control below it that has a CardView layout surrouned linearlayout. no the problem is that the nested scroll overlap the toolbar like this i show in image enter image description here

and also in run time it pass the app like there is no toolbar like this:

enter image description here

enter image description here

this is my code:

<?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/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >
   <android.support.design.widget.AppBarLayout
      android:id="@+id/appbarLayout"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:fitsSystemWindows="true"
      >



<android.support.v7.widget.Toolbar
    android:id="@+id/toolbar"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@color/colorPrimary"
    android:elevation="7dp"
    app:theme="@style/ThemeOverlay.AppCompat"
    android:popupTheme="@style/ThemeOverlay.AppCompat.Light"

    android:titleTextColor="@color/colorPrimary"
    app:layout_scrollFlags="scroll|enterAlways"
    ></android.support.v7.widget.Toolbar>
    </android.support.design.widget.AppBarLayout>

    <android.support.v4.widget.NestedScrollView

        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:nestedScrollingEnabled="true"

        >

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical"
            android:paddingTop="10dp"

            >
            <include layout="@layout/scroll_view_item" />
            <include layout="@layout/scroll_view_item" />
            <include layout="@layout/scroll_view_item" />
            <include layout="@layout/scroll_view_item" />
            <include layout="@layout/scroll_view_item" />
            <include layout="@layout/scroll_view_item" />
            <include layout="@layout/scroll_view_item" />
            <include layout="@layout/scroll_view_item" />
        </LinearLayout>

    </android.support.v4.widget.NestedScrollView>

</android.support.design.widget.CoordinatorLayout>

scroll_view_item code is here:

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.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="16dp"
    android:elevation="5dp"
    app:cardCornerRadius="5dp">
<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="15dp"
    android:orientation="vertical"

    >
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Dummy Header"
        android:textColor="@android:color/holo_red_light"
        android:textSize="20sp"
        android:textStyle="bold"
        />
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp"
        android:text="@string/app_text"
        />

</LinearLayout>
</android.support.v7.widget.CardView>

Answer

just surround your code with linearlayout like this:

<?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/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        >
   <android.support.design.widget.AppBarLayout
      android:id="@+id/appbarLayout"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:fitsSystemWindows="true"
      >



<android.support.v7.widget.Toolbar
    android:id="@+id/toolbar"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@color/colorPrimary"
    android:elevation="7dp"
    app:theme="@style/ThemeOverlay.AppCompat"
    android:popupTheme="@style/ThemeOverlay.AppCompat.Light"

    android:titleTextColor="@color/colorPrimary"
    app:layout_scrollFlags="scroll|enterAlways"
    ></android.support.v7.widget.Toolbar>
    </android.support.design.widget.AppBarLayout>

    <android.support.v4.widget.NestedScrollView

        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:nestedScrollingEnabled="true"

        >

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical"
            android:paddingTop="10dp"

            >
            <include layout="@layout/scroll_view_item" />
            <include layout="@layout/scroll_view_item" />
            <include layout="@layout/scroll_view_item" />
            <include layout="@layout/scroll_view_item" />
            <include layout="@layout/scroll_view_item" />
            <include layout="@layout/scroll_view_item" />
            <include layout="@layout/scroll_view_item" />
            <include layout="@layout/scroll_view_item" />
        </LinearLayout>

    </android.support.v4.widget.NestedScrollView>
    </LinearLayout>
</android.support.design.widget.CoordinatorLayout>
Categories
discuss

Writing HashMap contents to the file

I have a HashMap<Integer, Integer>. I write its content to the file, so each line of it contains hashmapKey:::hashmapValue. This is how I do it now:

List<String> mLines = new ArrayList<String>();
mHashMap.forEach((key, value) -> mLines.add(key + DATA_SEPARATOR + value));
Files.write(mOutputPath, mLines, StandardCharsets.UTF_8);

I very doubt that I need to copy entire HashMap to the list of strings, I am sure it will give me performance issues when working with big amounts of data. My question is: how can I write HashMap contents to the file using Java 8 avoiding copying values in another list?

Answer

The simplest, non-copying, most “streamish” solution is

Files.write(mOutputPath, () -> mHashMap.entrySet().stream()
    .<CharSequence>map(e -> e.getKey() + DATA_SEPARATOR + e.getValue())
    .iterator());

While a Stream does not implement Iterable, a lambda expression performing a Stream operation that ends with calling iterator() on the stream, can be. It will fulfill the contract as the lambda expression will, unlike a Stream, produce a new Iterator on each invocation.

Note that I removed the explicit UTF-8 character set specifier as java.nio.Files will use UTF-8 when no charset is specified (unlike the old io classes).

The neat thing about the above solution is that the I/O operation wraps the Stream processing, so inside the Stream, we don’t have to deal with checked exceptions. In contrast, the Writer+forEach solution needs to handle IOExceptions as a BiConsumer is not allowed to throw checked exceptions. As a result, a working solution using forEach would look like:

try(Writer writer = Files.newBufferedWriter(mOutputPath)) {
    mHashMap.forEach((key, value) -> {
        try { writer.write(key + DATA_SEPARATOR + value + System.lineSeparator()); }
        catch (IOException ex) { throw new UncheckedIOException(ex); }
    });
} catch(UncheckedIOException ex) { throw ex.getCause(); }
Categories
discuss

Sticky ScrollView Item at the Bottom – Android

I wanted to implement a sticky scrollview item which sticks at the bottom of the screen. Below are a couple of screenshots to explain my question.

  1. The below screen shows the fixed view/layout at the bottom of the screen saying ‘Save to and Add to Bag’

Layout/View Stuck to the bottom of the page

  1. When the user scrolls down the page, the layout/view scrolls with the page. As shown in the below screen.

The layout/view scrolling with the page

Things i have tried:

1.StickyScrollViewItems by emilsjolander: https://github.com/emilsjolander/StickyScrollViewItems/blob/master/library/src/com/emilsjolander/components/StickyScrollViewItems/StickyScrollView.java

I tried to reverse the header to the bottom, but no luck!

Your help will be deeply appreciated.

Thank you.

EDIT:

Following is the scrollview I tried to make. The sticky view still sticks at the top, where as it should stick to the bottom.

public class StickyScrollView extends ScrollView {

/**
 * Tag for views that should stick and have constant drawing. e.g. TextViews, ImageViews etc
 */
public static final String STICKY_TAG = "sticky";

/**
 * Flag for views that should stick and have non-constant drawing. e.g. Buttons, ProgressBars etc
 */
public static final String FLAG_NONCONSTANT = "-nonconstant";

/**
 * Flag for views that have aren't fully opaque
 */
public static final String FLAG_HASTRANSPARANCY = "-hastransparancy";

/**
 * Default height of the shadow peeking out below the stuck view.
 */
private static final int DEFAULT_SHADOW_HEIGHT = 10; // dp;

private ArrayList<View> stickyViews;
private View currentlyStickingView;
private float stickyViewTopOffset, stickViewBottomOffset;
private int stickyViewLeftOffset;
private boolean redirectTouchesToStickyView;
private boolean clippingToPadding;
private boolean clipToPaddingHasBeenSet;

private int mShadowHeight;
private Drawable mShadowDrawable;

private final Runnable invalidateRunnable = new Runnable() {

    @Override
    public void run() {
        if (currentlyStickingView != null) {
            int l = getLeftForViewRelativeOnlyChild(currentlyStickingView);
            int t = getBottomForViewRelativeOnlyChild(currentlyStickingView);
            int r = getRightForViewRelativeOnlyChild(currentlyStickingView);
            //int b = (int) (getScrollY() + (currentlyStickingView.getHeight() + stickyViewTopOffset));
            int b = getBottomForViewRelativeOnlyChild(currentlyStickingView);
            invalidate(l, t, r, b);
        }
        postDelayed(this, 16);
    }
};

public StickyScrollView(Context context) {
    this(context, null);
}

public StickyScrollView(Context context, AttributeSet attrs) {
    this(context, attrs, android.R.attr.scrollViewStyle);
}

public StickyScrollView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    setup();

    TypedArray a = context.obtainStyledAttributes(attrs,
            R.styleable.StickyScrollView, defStyle, 0);

    final float density = context.getResources().getDisplayMetrics().density;
    int defaultShadowHeightInPix = (int) (DEFAULT_SHADOW_HEIGHT * density + 0.5f);

    mShadowHeight = a.getDimensionPixelSize(
            R.styleable.StickyScrollView_stuckShadowHeight,
            defaultShadowHeightInPix);

    int shadowDrawableRes = a.getResourceId(
            R.styleable.StickyScrollView_stuckShadowDrawable, -1);

    if (shadowDrawableRes != -1) {
        mShadowDrawable = context.getResources().getDrawable(
                shadowDrawableRes);
    }

    a.recycle();

}

/**
 * Sets the height of the shadow drawable in pixels.
 *
 * @param height
 */
public void setShadowHeight(int height) {
    mShadowHeight = height;
}


public void setup() {
    stickyViews = new ArrayList<View>();
}

private int getLeftForViewRelativeOnlyChild(View v) {
    int left = v.getLeft();
    while (v.getParent() != getChildAt(0)) {
        v = (View) v.getParent();
        left += v.getLeft();
    }
    return left;
}

private int getTopForViewRelativeOnlyChild(View v) {
    int top = v.getTop();
    while (v.getParent() != getChildAt(0)) {
        v = (View) v.getParent();
        top += v.getTop();
    }
    return top;
}

private int getRightForViewRelativeOnlyChild(View v) {
    int right = v.getRight();
    while (v.getParent() != getChildAt(0)) {
        v = (View) v.getParent();
        right += v.getRight();
    }
    return right;
}

private int getBottomForViewRelativeOnlyChild(View v) {
    int bottom = v.getBottom();
    while (v.getParent() != getChildAt(0)) {
        v = (View) v.getParent();
        bottom += v.getBottom();
    }
    return bottom;
}

@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
    super.onLayout(changed, l, t, r, b);
    if (!clipToPaddingHasBeenSet) {
        clippingToPadding = true;
    }
    notifyHierarchyChanged();
}

@Override
public void setClipToPadding(boolean clipToPadding) {
    super.setClipToPadding(clipToPadding);
    clippingToPadding = clipToPadding;
    clipToPaddingHasBeenSet = true;
}

@Override
public void addView(View child) {
    super.addView(child);
    findStickyViews(child);
}

@Override
public void addView(View child, int index) {
    super.addView(child, index);
    findStickyViews(child);
}

@Override
public void addView(View child, int index, android.view.ViewGroup.LayoutParams params) {
    super.addView(child, index, params);
    findStickyViews(child);
}

@Override
public void addView(View child, int width, int height) {
    super.addView(child, width, height);
    findStickyViews(child);
}

@Override
public void addView(View child, android.view.ViewGroup.LayoutParams params) {
    super.addView(child, params);
    findStickyViews(child);
}

@Override
protected void dispatchDraw(Canvas canvas) {
    super.dispatchDraw(canvas);
    if (currentlyStickingView != null) {
        canvas.save();
        //canvas.translate(getPaddingLeft() + stickyViewLeftOffset, getScrollY() + stickyViewTopOffset + (clippingToPadding ? getPaddingTop() : 0));
        canvas.translate(getPaddingLeft() + stickyViewLeftOffset, getScrollY() - stickViewBottomOffset + (clippingToPadding ? getPaddingBottom() : 0));

        //canvas.clipRect(0, (clippingToPadding ? -stickyViewTopOffset : 0),
        //getWidth() - stickyViewLeftOffset,
        //currentlyStickingView.getHeight() + mShadowHeight + 1);

        canvas.clipRect(0, currentlyStickingView.getHeight() - mShadowHeight, getWidth() - stickyViewLeftOffset, (clippingToPadding ? 0 : stickViewBottomOffset));

        if (mShadowDrawable != null) {
            int left = 0;
            int right = currentlyStickingView.getWidth();
            int top = currentlyStickingView.getHeight();
            int bottom = currentlyStickingView.getHeight() + mShadowHeight;
            mShadowDrawable.setBounds(left, top, right, bottom);
            mShadowDrawable.draw(canvas);
        }

        //canvas.clipRect(0, (clippingToPadding ? -stickyViewTopOffset : 0), getWidth(), currentlyStickingView.getHeight());
        canvas.clipRect(0, currentlyStickingView.getHeight(), getWidth(), (clippingToPadding ? 0 : stickViewBottomOffset));
        if (getStringTagForView(currentlyStickingView).contains(FLAG_HASTRANSPARANCY)) {
            showView(currentlyStickingView);
            currentlyStickingView.draw(canvas);
            hideView(currentlyStickingView);
        } else {
            currentlyStickingView.draw(canvas);
        }
        canvas.restore();
    }
}

@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
    if (ev.getAction() == MotionEvent.ACTION_DOWN) {
        redirectTouchesToStickyView = true;
    }

    if (redirectTouchesToStickyView) {
        redirectTouchesToStickyView = currentlyStickingView != null;
        if (redirectTouchesToStickyView) {
            redirectTouchesToStickyView =
                    //ev.getY() <= (currentlyStickingView.getHeight() + stickyViewTopOffset)
                    ev.getY() <= (currentlyStickingView.getHeight() - stickViewBottomOffset) &&
                            ev.getX() >= getLeftForViewRelativeOnlyChild(currentlyStickingView) &&
                            ev.getX() <= getRightForViewRelativeOnlyChild(currentlyStickingView);
        }
    } else if (currentlyStickingView == null) {
        redirectTouchesToStickyView = false;
    }
    if (redirectTouchesToStickyView) {
        //ev.offsetLocation(0, -1 * ((getScrollY() + stickyViewTopOffset) - getTopForViewRelativeOnlyChild(currentlyStickingView)));
        ev.offsetLocation(0, 1 * ((getScrollY() + stickViewBottomOffset) - getBottomForViewRelativeOnlyChild(currentlyStickingView)));
    }
    return super.dispatchTouchEvent(ev);
}

private boolean hasNotDoneActionDown = true;

@Override
public boolean onTouchEvent(MotionEvent ev) {
    if (redirectTouchesToStickyView) {
        //ev.offsetLocation(0, ((getScrollY() + stickyViewTopOffset) - getTopForViewRelativeOnlyChild(currentlyStickingView)));
        ev.offsetLocation(0, ((getScrollY() - stickViewBottomOffset) - getTopForViewRelativeOnlyChild(currentlyStickingView)));
    }

    if (ev.getAction() == MotionEvent.ACTION_DOWN) {
        hasNotDoneActionDown = false;
    }

    if (hasNotDoneActionDown) {
        MotionEvent down = MotionEvent.obtain(ev);
        down.setAction(MotionEvent.ACTION_DOWN);
        super.onTouchEvent(down);
        hasNotDoneActionDown = false;
    }

    if (ev.getAction() == MotionEvent.ACTION_UP || ev.getAction() == MotionEvent.ACTION_CANCEL) {
        hasNotDoneActionDown = true;
    }

    return super.onTouchEvent(ev);
}

@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
    super.onScrollChanged(l, t, oldl, oldt);
    doTheStickyThing();
}

private void doTheStickyThing() {
    View viewThatShouldStick = null;
    View approachingView = null;
    for (View v : stickyViews) {
        int viewTop = getTopForViewRelativeOnlyChild(v) - getScrollY() + (clippingToPadding ? 0 : getPaddingTop());
        int viewBottom = getBottomForViewRelativeOnlyChild(v) - getScrollY() + (clippingToPadding ? 0 : getPaddingBottom());
        Log.e("VIEW BOTTOM: ", "VIEW BOTTOM: " + viewBottom);

        //Log.e("VIEW TOP: ", "VIEW TOP: " + viewTop);

        //BOTTOM
        if (viewBottom >= 0) {
            if (viewThatShouldStick == null || viewBottom > (getBottomForViewRelativeOnlyChild(viewThatShouldStick) - getScrollY() + (clippingToPadding ? 0 : getPaddingBottom()))) {
                viewThatShouldStick = v;
                Log.e("VIEW BOTTOM: ", "VIEW THAT SHOULD STICK: " + viewThatShouldStick);
            }
        } else {
            if (approachingView == null || viewBottom < (getBottomForViewRelativeOnlyChild(approachingView) - getScrollY() + (clippingToPadding ? 0 : getPaddingBottom()))) {
                approachingView = v;
                Log.e("VIEW BOTTOM: ", "APPROACHING VIEW: " + approachingView);
            }
        }

        //            //TOP
        //            if (viewTop <= 0) {
        //                if (viewThatShouldStick == null || viewTop > (getTopForViewRelativeOnlyChild(viewThatShouldStick) - getScrollY() + (clippingToPadding ? 0 : getPaddingTop()))) {
        //                    viewThatShouldStick = v;
        //                }
        //            } else {
        //                if (approachingView == null || viewTop < (getTopForViewRelativeOnlyChild(approachingView) - getScrollY() + (clippingToPadding ? 0 : getPaddingTop()))) {
        //                    approachingView = v;
        //                }
        //            }
    }

    //BOTTOM
    if (viewThatShouldStick != null) {
        stickViewBottomOffset = approachingView == null ? 0 : Math.min(0, getBottomForViewRelativeOnlyChild(approachingView) - getScrollY() + (clippingToPadding ? 0 : getPaddingBottom() - viewThatShouldStick.getHeight()));
        if (viewThatShouldStick != currentlyStickingView) {
            if (currentlyStickingView != null) {
                stopStickingCurrentlyStickingView();
                Log.e("BOTTOM UNSTUCK: ", "BOTTOM UNSTUCK: ");
            }
            stickyViewLeftOffset = getLeftForViewRelativeOnlyChild(viewThatShouldStick);
            startStickingView(viewThatShouldStick);
            Log.e("BOTTOM STUCK: ", "BOTTOM STUCK: " + viewThatShouldStick);
        }
    } else if (currentlyStickingView != null) {
        Log.e("BOTTOM UNSTUCK: ", "BOTTOM UNSTUCK: ");
        stopStickingCurrentlyStickingView();
    }

    //TOP
    //        if (viewThatShouldStick != null) {
    //            stickyViewTopOffset = approachingView == null ? 0 : Math.min(0, getTopForViewRelativeOnlyChild(approachingView) - getScrollY() + (clippingToPadding ? 0 : getPaddingTop()) - viewThatShouldStick.getHeight());
    ////            Log.e("VIEW TOP: ", "STICKY VIEW TOP OFFSET: " + stickyViewTopOffset);
    //            if (viewThatShouldStick != currentlyStickingView) {
    //                if (currentlyStickingView != null) {
    //                    stopStickingCurrentlyStickingView();
    //                }
    //                // only compute the left offset when we start sticking.
    //                stickyViewLeftOffset = getLeftForViewRelativeOnlyChild(viewThatShouldStick);
    //                startStickingView(viewThatShouldStick);
    //            }
    //        } else if (currentlyStickingView != null) {
    //            stopStickingCurrentlyStickingView();
    //        }
}

private void startStickingView(View viewThatShouldStick) {
    currentlyStickingView = viewThatShouldStick;
    if (getStringTagForView(currentlyStickingView).contains(FLAG_HASTRANSPARANCY)) {
        hideView(currentlyStickingView);
    }
    if (((String) currentlyStickingView.getTag()).contains(FLAG_NONCONSTANT)) {
        post(invalidateRunnable);
    }
}

private void stopStickingCurrentlyStickingView() {
    if (getStringTagForView(currentlyStickingView).contains(FLAG_HASTRANSPARANCY)) {
        showView(currentlyStickingView);
    }
    currentlyStickingView = null;
    removeCallbacks(invalidateRunnable);
}

/**
 * Notify that the sticky attribute has been added or removed from one or more views in the View hierarchy
 */
public void notifyStickyAttributeChanged() {
    notifyHierarchyChanged();
}

private void notifyHierarchyChanged() {
    if (currentlyStickingView != null) {
        stopStickingCurrentlyStickingView();
    }
    stickyViews.clear();
    findStickyViews(getChildAt(0));
    doTheStickyThing();
    invalidate();
}

private void findStickyViews(View v) {
    if (v instanceof ViewGroup) {
        ViewGroup vg = (ViewGroup) v;
        for (int i = 0; i < vg.getChildCount(); i++) {
            String tag = getStringTagForView(vg.getChildAt(i));
            if (tag != null && tag.contains(STICKY_TAG)) {
                stickyViews.add(vg.getChildAt(i));
            } else if (vg.getChildAt(i) instanceof ViewGroup) {
                findStickyViews(vg.getChildAt(i));
            }
        }
    } else {
        String tag = (String) v.getTag();
        if (tag != null && tag.contains(STICKY_TAG)) {
            stickyViews.add(v);
        }
    }
}

private String getStringTagForView(View v) {
    Object tagObject = v.getTag();
    return String.valueOf(tagObject);
}

private void hideView(View v) {
    if (Build.VERSION.SDK_INT >= 11) {
        v.setAlpha(0);
    } else {
        AlphaAnimation anim = new AlphaAnimation(1, 0);
        anim.setDuration(0);
        anim.setFillAfter(true);
        v.startAnimation(anim);
    }
}

private void showView(View v) {
    if (Build.VERSION.SDK_INT >= 11) {
        v.setAlpha(1);
    } else {
        AlphaAnimation anim = new AlphaAnimation(0, 1);
        anim.setDuration(0);
        anim.setFillAfter(true);
        v.startAnimation(anim);
    }
}
}

Answer

I have the same requirement to implement this kind of view and i have figured out solution as per my code and logic. So you can apply code which i am sharing with you!

Below is the my project image how it is working using my code.

enter image description here

Layout XML

  <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout 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="match_parent"
        android:background="@color/white"
        android:orientation="vertical">
     <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="56dp"
        android:background="@color/red">


// Fix header For Product Name

</RelativeLayout>
         <ScrollView
                android:id="@+id/scroll_main"
                android:layout_width="match_parent"
                android:layout_height="0dp"
                android:layout_weight="0.5">

        <LinearLayout
                        android:id="@+id/lin_upper"
                        android:layout_width="match_parent"
                        android:layout_height="match_parent"
                        android:orientation="vertical">

        /// For the Conternt that you want to put upper Side OF bottom View that is Fix>> In my case pager, PagerIndicator ,ProductName, Price ,Size And size list>>

        // Create this to get Upper Content height.. And Put your Content..


        </LinearLayout>
         <LinearLayout
                        android:id="@+id/llin_inner_button"
                        android:layout_width="match_parent"
                        android:layout_height="48dp"
                        android:orientation="horizontal"
                        android:visibility="visible">

        // Copy Bottom View that you want to Stick

        </LinearLayout>
         <TextView
                        android:id="@+id/txt_temp"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_marginLeft="8dp"
                        android:layout_marginTop="8dp"
                        android:text="Lorazepam belongs to a group of drugs"/>

        </ScrollView>

        <LinearLayout
                android:id="@+id/llin_outer_button"
                android:layout_width="match_parent"
                android:layout_height="48dp"
                android:orientation="horizontal">

        // Your actual BottomView Here...

        </LinearLayout>

    </LinearLayout>

Java File

Declare your variables

 private int lay_height = 0;
 int height = 0;

Now you need to get your height as per device screen height including status bar height and soft buttons height and you need to add header height(if necessary) in to total height.

 public int getStatusBarHeight() {
    int result = 0;
    int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
    if (resourceId > 0) {
        result = getResources().getDimensionPixelSize(resourceId);
    }
    return result;
}

@SuppressLint("NewApi")
private int getSoftButtonsBarHeight() {
    // getRealMetrics is only available with API 17 and +
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
        DisplayMetrics metrics = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(metrics);
        int usableHeight = metrics.heightPixels;
        getWindowManager().getDefaultDisplay().getRealMetrics(metrics);
        int realHeight = metrics.heightPixels;
        if (realHeight > usableHeight)
            return realHeight - usableHeight;
        else
            return 0;
    }
    return 0;
}

public int pxToDp(int px) {
    DisplayMetrics displayMetrics = this.getResources().getDisplayMetrics();
    int dp = Math.round(px / (displayMetrics.xdpi / DisplayMetrics.DENSITY_DEFAULT));
    return dp;
}

public static float dipToPixels(Context context, float dipValue) {
    DisplayMetrics metrics = context.getResources().getDisplayMetrics();
    return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dipValue, metrics);
}

Calculate Height

    Display display = getWindowManager().getDefaultDisplay();
    Point size = new Point();
    display.getSize(size);
    int width = size.x;


    if (getSoftButtonsBarHeight() == 0) {
        height = size.y - getStatusBarHeight() - getSoftButtonsBarHeight() - (int) dipToPixels(ProductDetailActivity.this, 104);

    } else {
        height = size.y - getStatusBarHeight() - getSoftButtonsBarHeight() - (int) dipToPixels(ProductDetailActivity.this, 56);
    }

    Log.v("height_sc", height + "" + "   " + getStatusBarHeight() + "  " + getSoftButtonsBarHeight() + "   " + size.y);

    ViewTreeObserver observer = lin_upper.getViewTreeObserver();
    observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {

        @Override
        public void onGlobalLayout() {
            // TODO Auto-generated method stub
            lay_height = lin_upper.getHeight();
            int headerLayoutWidth = lin_upper.getWidth();
            lin_upper.getViewTreeObserver().removeGlobalOnLayoutListener(
                    this);

            Log.v("height", lay_height + "");
        }
    });

Now you need to implement functionality for scroll view in onScrollChanged() method.

 scroll_main.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {

        @Override
        public void onScrollChanged() {
            new Handler().post(new Runnable() {
                @Override
                public void run() {
                    int scrollX = scroll_main.getScrollX(); //for horizontalScrollView
                    int scrollY = scroll_main.getScrollY(); //for verticalScrollView


                    int sc = scrollY + height;

                    Log.v("bottom", lay_height + "  Y=" + sc + "  " + scrollY + "   " + height);

                    if (sc >= lay_height) {

                        llin_outer_button.setVisibility(View.GONE);

                    } else {
                        llin_outer_button.setVisibility(View.VISIBLE);
                    }
                }
            });
        }
    });
Source: stackoverflow
Text is available under the Creative Commons Attribution-ShareAlike License; additional terms may apply. By using this site, you agree to the Privacy Policy, and Copyright Policy. Content is available under CC BY-SA 3.0 unless otherwise noted. The answers/resolutions are collected from stackoverflow, are licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0 © No Copyrights, All Questions are retrived from public domain..