简体   繁体   中英

How can I anchor an image to the center within an Imageview in a scrollview, in Android?

When I scroll within my Android scrollview, it scrolls down as it should.

But I'd like the image within the imageview to anchor to the centre. So you always see the face of the person in the image as you scrolling up.

So far I have not been able to accomplish this

A similar effect is created in the image below:

在此输入图像描述

Stockguy image:

在此输入图像描述

My code so far (which so far doesn't accomplish this):

<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:fillViewport="true"
    android:scrollbars="none"
    android:background="#FAFAFA"
    android:id="@+id/cScrollview"
    >

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="1100dp"
    tools:context=".MainActivity"
    android:id="@+id/CRLayout">

        <ImageView
            android:layout_gravity="center"
            android:adjustViewBounds="true"
            android:layout_width="601dp"
            android:layout_height="250dp"
            android:paddingTop="0dp"
            android:paddingLeft="0dp"
            android:paddingRight="0dp"
            android:scaleType="centerCrop"
            android:id="@+id/contactPic"
            android:src="@drawable/stockguy"/>

            ....


            </RelativeLayout>
</ScrollView>

To achieve parallax effect like on image you posted try following code. It is a very simple way.

Layout:

<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/scrollView"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <RelativeLayout
        android:id="@+id/rlWrapper"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <ImageView
            android:id="@+id/ivContactPhoto"
            android:layout_width="match_parent"
            android:layout_height="@dimen/contact_photo_height"
            android:scaleType="centerCrop"
            android:src="@drawable/stockguy" />

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="@dimen/contact_photo_height"
            android:layout_marginTop="250dp">

            <!-- Other Views -->

        </LinearLayout>

    </RelativeLayout>
</ScrollView>

LinearLayout 's top margin is equal to the ImageViews 's height.

Listening scroll position of the ScrollView and changing position of ImageView :

@Override
protected void onCreate(Bundle savedInstanceState) {
    <...>

    mScrollView = (ScrollView) findViewById(R.id.scrollView);
    mPhotoIV = (ImageView) findViewById(R.id.ivContactPhoto);
    mWrapperRL = (RelativeLayout) findViewById(R.id.rlWrapper);

    mScrollView.getViewTreeObserver().addOnScrollChangedListener(new ScrollPositionObserver());

    <...>
}

private class ScrollPositionObserver implements ViewTreeObserver.OnScrollChangedListener {

    private int mImageViewHeight;

    public ScrollPositionObserver() {
        mImageViewHeight = getResources().getDimensionPixelSize(R.dimen.contact_photo_height);
    }

    @Override
    public void onScrollChanged() {
        int scrollY = Math.min(Math.max(mScrollView.getScrollY(), 0), mImageViewHeight);

        // changing position of ImageView
        mPhotoIV.setTranslationY(scrollY / 2);

        // alpha you can set to ActionBar background
        float alpha = scrollY / (float) mImageViewHeight;
    }
}

Hope it will help.

I'd take a different approach with that.

Try building your layout based on the following snippet:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
          android:orientation="vertical"
          android:layout_width="match_parent"
          android:layout_height="match_parent">
<ImageView
    android:id="@+id/image"
    android:layout_width="match_parent"
    android:background="#00FF00"
    android:scaleType="centerCrop"
    android:layout_height="200dp"/>
<FrameLayout
    android:id="@+id/content"
    android:layout_below="@+id/image"
    android:background="#FF0000"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>
</RelativeLayout>

Using the GestureDetector.SimpleOnGestureListener you can detect when the user scrolls on the content layout and update the image size and alpha accordingly to get the effect you describe.

I would implement this using a scroll callback on the ScrollView, this doesn't exist by default but is easy to create yourself by extending ScrollView:

public class UpdatingScrollView extends ScrollView {

    private OnScrollChangedListener mScrollChangedListener;

    public interface OnScrollChangedListener {
        public void onScrollChanged(int x, int y, int oldx, int oldy);
    }

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

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

    public UpdatingScrollView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    public void setOnScrollChangedListener(OnScrollChangedListener listener) {
        mScrollChangedListener = listener;
    }

    @Override
    protected void onScrollChanged(int x, int y, int oldx, int oldy) {
        super.onScrollChanged(x, y, oldx, oldy);
        if (mScrollChangedListener != null) mScrollChangedListener.onScrollChanged(x, y, oldx, oldy);
    }
}

So replace ScrollView in your layout with com.your.package.UpdatingScrollView .

In your Fragment/Activity where the UpdatingScrollView is defined you set the scroll listener and update the bottom margin of the image based on the scroll offset. For every 2 pixels the ScrollView has scrolled you'll want to update the bottom margin by -1 pixel which will make the image move up the screen at half the rate of the rest of the content.

So something like this:

scrollView.setOnScrollChangedListener(new OnScrollChangedListener() {
    @Override
    public void onScrollChanged(int x, int y, int oldx, int oldy) {
        // I think y will be negative when scrolled
        if(y >= -image.getHeight()) {
            RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) image.getLayoutParams();
            lp.setMargins(0, 0, 0, y / 2);
            image.setLayoutParams(lp);
        }
    }
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM