Anchor Location Based on Android

Keywords: Android less github xml

I believe that the front-end has done the function of page anchor location, through <a href="#head"> to set the page anchor location jump.
This article uses tablayout and scrollview to realize the function of android anchor location.
Design sketch:

Implementation ideas

1. Monitor scrollview sliding position, tablayout switch to corresponding label
2. Click on each tab of tablayout, scroll lview can slide to the corresponding area.

Custom scrollview

Because we need to monitor the sliding distance of scrollview in the sliding process, the user-defined scrollview exposes the sliding distance through the interface.

public class CustomScrollView extends ScrollView {

    public Callbacks mCallbacks;

    public CustomScrollView(Context context) {
        super(context);
    }

    public CustomScrollView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public CustomScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public void setCallbacks(Callbacks callbacks) {
        this.mCallbacks = callbacks;
    }

    @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
        super.onScrollChanged(l, t, oldl, oldt);
        if (mCallbacks != null) {
            mCallbacks.onScrollChanged(l, t, oldl, oldt);
        }
    }
    //Define interfaces for callbacks
    public interface Callbacks {
        void onScrollChanged(int x, int y, int oldx, int oldy);
    }

}

In the layout file, tablayout and Custom ScrollView are filled temporarily with Linear Layout.

<?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:orientation="vertical">

    <android.support.design.widget.TabLayout
        android:id="@+id/tablayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:tabIndicatorColor="@color/colorPrimary"
        app:tabMode="scrollable"
        app:tabSelectedTextColor="@color/colorPrimary" />

    <com.tabscroll.CustomScrollView
        android:id="@+id/scrollView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fillViewport="true"
        android:fitsSystemWindows="true">

        <LinearLayout
            android:id="@+id/container"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:padding="16dp">

        </LinearLayout>

    </com.tabscroll.CustomScrollView>

</LinearLayout>

Data simulation

Data simulation, dynamic addition of scrollview content, here customized AnchorView as the filling content for each block.

private String[] tabTxt = {"A living room", "Bedroom", "Restaurant", "Study", "balcony", "Children's room"};
//Collection of content block view s
private List<AnchorView> anchorList = new ArrayList<>();
//Is the interpretation caused by scrollview active sliding, true-yes, false-no, by tablayout?
private boolean isScroll;
//Record the last position to prevent sliding and relocating to tablayout in the same content block
private int lastPos;

//Analog data, fill scrollview
for (int i = 0; i < tabTxt.length; i++) {
    AnchorView anchorView = new AnchorView(this);
    anchorView.setAnchorTxt(tabTxt[i]);
    anchorView.setContentTxt(tabTxt[i]);
    anchorList.add(anchorView);
    container.addView(anchorView);
}

//tablayout setting label
for (int i = 0; i < tabTxt.length; i++) {
    tabLayout.addTab(tabLayout.newTab().setText(tabTxt[i]));
}

Define the variable marker isScroll to determine who caused the scrollview sliding and avoid the scrollview sliding problem caused by clicking tabLayout.
Define the variable flag lastPos, and when scrollview slides in the same module, it no longer calls tabLayout.setScrollPosition to refresh the label.

Customized AnhorView:

public class AnchorView extends LinearLayout {

    private TextView tvAnchor;
    private TextView tvContent;

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

    public AnchorView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public AnchorView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    private void init(Context context) {
        View view = LayoutInflater.from(context).inflate(R.layout.view_anchor, this, true);
        tvAnchor = view.findViewById(R.id.tv_anchor);
        tvContent = view.findViewById(R.id.tv_content);
        Random random = new Random();
        int r = random.nextInt(256);
        int g = random.nextInt(256);
        int b = random.nextInt(256);
        tvContent.setBackgroundColor(Color.rgb(r, g, b));
    }

    public void setAnchorTxt(String txt) {
        tvAnchor.setText(txt);
    }

    public void setContentTxt(String txt) {
        tvContent.setText(txt);
    }
}

Realization

Scollview's Sliding Monitor:

scrollView.setOnTouchListener(new View.OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        //When triggered by scrollview, isScroll sets true
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            isScroll = true;
        }
        return false;
    }
});

scrollView.setCallbacks(new CustomScrollView.Callbacks() {
    @Override
    public void onScrollChanged(int x, int y, int oldx, int oldy) {
        if (isScroll) {
            for (int i = tabTxt.length - 1; i >= 0; i--) {
                //According to the sliding distance, the height judgment of each module from the top of the parent layout is compared.
                if (y > anchorList.get(i).getTop() - 10) {
                    setScrollPos(i);
                    break;
                }
            }
        }
    }
});

//Switching Tags for Tablelayout
private void setScrollPos(int newPos) {
    if (lastPos != newPos) {
        //This method does not trigger tablayout onTabSelected listening
        tabLayout.setScrollPosition(newPos, 0, true);
    }
    lastPos = newPos;
}

tabLayout's click toggle:

tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
    @Override
    public void onTabSelected(TabLayout.Tab tab) {
        //Click on the label to slide scrollview and isScroll to set false
        isScroll = false;
        int pos = tab.getPosition();
        int top = anchorList.get(pos).getTop();
        scrollView.smoothScrollTo(0, top);
    }

    @Override
    public void onTabUnselected(TabLayout.Tab tab) {

    }

    @Override
    public void onTabReselected(TabLayout.Tab tab) {

    }
});

So far the effect has come out, but
The problem is that when you click on the last item, scrollView slides to the bottom and does not show the desired effect. When you want to slide to the last item, only the last piece of content is displayed on the full screen.
So here we need to deal with the height of the last view. When the full screen is not satisfied, reset the height of the last view and make it full by calculating.

//Monitor to determine the height of the last module, and fill the screen with the last module when the screen is less than one.
private ViewTreeObserver.OnGlobalLayoutListener listener;

listener = new ViewTreeObserver.OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout() {
        int screenH = getScreenHeight();
        int statusBarH = getStatusBarHeight(MainActivity.this);
        int tabH = tabLayout.getHeight();
        //Calculate the height of the content block, the height of the full screen - the height of the status bar - the height of the tablayout - the padding 16dp of the content container
        int lastH = screenH - statusBarH - tabH - 16 * 3;
        AnchorView lastView = anchorList.get(anchorList.size() - 1);
        //When the height of the last view is less than the height of the content block, set its height to be full
        if (lastView.getHeight() < lastH) {
            LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
            params.height = lastH;
            lastView.setLayoutParams(params);
        }
        container.getViewTreeObserver().removeOnGlobalLayoutListener(listener);

    }
};
container.getViewTreeObserver().addOnGlobalLayoutListener(listener);

In this way, the expected effect has been achieved.

At this point, the anchor location of tablayout + scrollview has been formed. In the actual project, we can also use tablayout + recyclerview to achieve the same effect, which will bring such articles in the future.

During this period of time, I am making a small program, including data crawling + background + small program, it may take some time to come out, mainly the data crawler side of the more troublesome... Look forward!

See the detailed code
github address: https://github.com/taixiang/tabScroll

Welcome to my blog: https://blog.manjiexiang.cn/
More wonderful welcome to pay attention to micro-signal: 10 miles of spring breeze is better to know you

There is a "Buddhist Family Nung Circle". Welcome to join us for a chat. Just have fun!

It's out of date, but add me to Wechat tx467220125 to pull you into the group.

Posted by FireyIce01 on Sat, 11 May 2019 22:03:55 -0700