应用程序背景中的视差效果

时间:2014-10-04 13:52:30

标签: android parallax

我是Android世界的新手。我想在我的应用程序中添加一些视差背景效果。

我该怎么办?如何在Android中解决此问题?

是否有任何有效的方法来创建 2-3层视差背景? android API中是否有一些工具或类?

或者我可能需要在代码中“手动”修改背景图像位置或边距?

我正在使用API​​级别19。

我试图理解Paralloid库,但这个太大了,无法解释。我是Android和Java的新手,我不熟悉所有Layouts和其他UI对象,但我对MVC很熟悉。

我开始赏金,也许有人可以一步一步解释这个图书馆的运作方式。

7 个答案:

答案 0 :(得分:11)

这是你可以做的:

在您的活动/片段布局文件中指定2个ScrollView(例如background_sv和content_sv)。

<?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:layout_width="match_parent"
    android:layout_height="match_parent" >

    <com.example.parallax.MyScrollView
        android:id="@+id/background_sv"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >

            <ImageView
                android:id="@+id/parallax_bg"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="..." />
    </com.example.parallax.MyScrollView>

    <com.example.parallax.MyScrollView
        android:id="@+id/content_sv"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical" >
        </LinearLayout>
    </com.example.parallax.MyScrollView>

</RelativeLayout>

在背景高度的内容滚动视图中添加虚拟视图,并使其透明。现在,将滚动侦听器附加到content_sv。滚动内容滚动视图时,请调用

mBgScrollView.scrollTo(0, (int)(y /*scroll Of content_sv*/ / 2f));

现有的API没有获得滚动事件的支持。 因此,我们需要创建一个Custom ScrollView来提供ScrollViewListener。

package com.example.parallax;

// imports;

public class MyScrollView extends ScrollView {

    public interface ScrollViewListener {
        void onScrollChanged(MyScrollView scrollView, int x, int y, int oldx, int oldy);
    }

    private ScrollViewListener scrollViewListener = null;

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

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

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

    public void setScrollViewListener(ScrollViewListener scrollViewListener) {
        this.scrollViewListener = scrollViewListener;
    }

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

这是托管内容ScrollView和后台ScrollView

的活动
package com.example.parallax;

// imports;

public class ParallaxActivity extends Activity implements ScrollViewListener {

    private MyScrollView mBgScrollView;
    private MyScrollView mContentScrollView;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        mBgScrollView = findViewById(R.id.background_sv);
        mContentScrollView = findViewById(R.id.content_sv);
        mContentScrollView.setOnScrollListener(this);
    }

    // this is method for onScrollListener put values according to your need
    @Override
    public void onScrollChanged(MyScrollView scrollView, int x, int y, int oldx, int oldy) {
        super.onScrollChanged(scrollView, x, y, oldx, oldy);
        // when the content scrollview will scroll by say 100px, 
        // the background scrollview will scroll by 50px. It will 
        // look like a parallax effect where the background is 
        // scrolling with a different speed then the content scrollview.
        mBgScrollView.scrollTo(0, (int)(y / 2f));
    }
}

答案 1 :(得分:4)

我认为这个问题不清楚,所以这不是一个真正的答案,而是试图澄清比我在评论中所包含的更多细节。

我的问题是你想要达到什么样的视差效果。鉴于这三个示例(它们是您可以从Play商店安装的演示应用程序),如果有任何类型的视差效果你想要?请在评论中回答。

给出答案,我们都会发现帮助更容易。如果您编辑问题以包含此信息,则会对其进行改进。

答案 2 :(得分:2)

以下内容包含Paralloid的作者发布的示例应用程序:

https://github.com/chrisjenx/Paralloid/tree/master/paralloidexample

从“使用入门”部分下的GitHub页面:

  

布局

     

<强>滚动型

     

这是一个例子,请参阅paralloidexample App   代码。

<FrameLayout ..>
<FrameLayout
        android:id="@+id/top_content"
            android:layout_width="match_parent"
            android:layout_height="192dp"/>

<uk.co.chrisjenx.paralloid.views.ParallaxScrollView
        android:id="@+id/scroll_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fillViewport="true">

    <LinearLayout
        android:id="@+id/scroll_content"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:paddingTop="192dp"/>

</uk.co.chrisjenx.paralloid.views.ParallaxScrollView>
</FrameLayout>
     

<强>片段

     

onViewCreated()onCreateView()

//...
FrameLayout topContent = (FrameLayout) rootView.findViewById(R.id.top_content);
ScrollView scrollView = (ScrollView) rootView.findViewById(R.id.scroll_view);
if (scrollView instanceof Parallaxor) {
        ((Parallaxor) scrollView).parallaxViewBy(topContent, 0.5f);
}
// TODO: add content to top/scroll content
     

多数民众赞成!

     

查看适用Parallax的Parallaxor界面   方法

希望这有帮助!

此外,here是指向Google的“入门”页面的链接。

此外,here是指向“初学者的Java教程”的链接。

以及有关布局的一些文档的link,以及“定义用户界面的可视化结构”。

话虽如此,您将使用布局来定义界面的外观,并使用后续的示例代码来定义与您交互时发生的情况。

P.S。您可以在行动here

中查看该应用程序

答案 3 :(得分:1)

我使用ParallaxScroll library。非常容易使用,样品很好并且记录良好。

答案 4 :(得分:1)

以下是使用ScrollView及其背景图片的方法。我已在github中提交了代码。

您需要扩展ScrollViewDrawable类。

  1. 默认情况下,ScrollView背景高度与视口高度相同。要实现视差效果,背景高度应该更大,并且应该基于ScrollView子高度和我们想要施加的背景滚动因子。 背景滚动因子为1表示,背景高度与ScrollView子高度相同,因此背景将以与子滚动相同的偏移滚动。 0.5表示,背景高度是ScrollView子扩展高度的0.5倍,并且与子内容相比将滚动50%。这有效地带来了视差滚动效果。
  2. 从ScrollView构造函数调用以下方法:

    void init() {
        // Calculate background drawable size before first draw of scrollview
        getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
            @Override
            public boolean onPreDraw() {
                // Remove the listener
                getViewTreeObserver().removeOnPreDrawListener(this);
    
                mDrawable = (ParallaxDrawable) getBackground();
    
                if(mDrawable != null && mDrawable instanceof ParallaxDrawable) {
                    // Get the only child of scrollview
                    View child = getChildAt(0);
                    int width = child.getWidth();
                    // calculate height of background based on child height and scroll factor
                    int height = (int) (getHeight() + (child.getHeight() - getHeight()) * mScrollFactor);
                    mDrawable.setSize(width, height);
                }       
    
                return true;
            }       
        });     
    }
    
    1. 滚动ScrollView时,在绘制背景时考虑滚动偏移。这基本上实现了视差效果。
    2. ParallaxScrollView:

      protected void onScrollChanged(int x, int y, int oldX, int oldY) {
         if(mDrawable != null && mDrawable instanceof ParallaxDrawable) {
             // set the scroll offset for the background drawable.
             mDrawable.setScrollOffset(x*mScrollFactor, y*mScrollFactor);
         }
      } 
      

      ParallaxDrawable:

      @Override
      public void draw(Canvas canvas) {
          // To move the background up, translate canvas by negative offset
          canvas.translate(-mScrollXOffset, -mScrollYOffset);
          mDrawable.draw(canvas);
          canvas.translate(mScrollXOffset, mScrollYOffset);
      }
      
      
      protected void onBoundsChange(Rect bounds) {
          // This sets the size of background drawable.
          mDrawable.setBounds(new Rect(bounds.top, bounds.left, bounds.left + mWidth, bounds.top + mHeight));
      }
      

      使用ParallaxScrollView和ParallaxDrawable:

      public class MyActivity extends Activity {
      
          @Override
          protected void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              setContentView(R.layout.parallax_layout);
      
              final ParallaxScrollView scrollView = (ParallaxScrollView) findViewById(R.id.sv);
              ParallaxDrawable drawable = new ParallaxDrawable(getResources().getDrawable(R.drawable.bg));
              scrollView.setBackground( drawable, 0.2f );
          }
      }
      

      parallax_layout.xml:

      <manish.com.parallax.ParallaxScrollView
              xmlns:android="http://schemas.android.com/apk/res/android"
              android:id="@+id/sv"
              android:layout_width="match_parent"
              android:layout_height="match_parent" >
      
              <LinearLayout
                  android:layout_width="match_parent"
                  android:layout_height="match_parent"
                  android:orientation="vertical">
      
                  <TextView
                      android:id="@+id/tv"
                      android:layout_width="wrap_content"
                      android:layout_height="wrap_content"
                      android:textColor="#fff"
                      android:text="@string/text" />
      
                  <View
                      android:layout_width="match_parent"
                      android:layout_height="5dp" />
                  ...
              </LinearLayout>
      </manish.com.parallax.ParallaxScrollView>
      

答案 5 :(得分:0)

Android API不支持太多具体的工具,您可能已经注意到了。在API 20中,他们添加了高程,这是深度的属性。这不支持视差布局本身,但我认为这是Google迈出的一步,使这种工作更容易。如果您想要在何时何地进行猜测,我会说在发布API 25之前可以根据最新更新和电池效率的进展添加视差实用程序。

现在您只需要听取某种动作并根据代表高程的值更改视图位置。

你的问题让我升级了我自己的项目,这就是我在片段中使用ViewDragHelper的方式。

public class MainFragment extends Fragment implements View.OnTouchListener {
    private ImageView mDecor, mBamboo, mBackgroundBamboo;
    private RelativeLayout mRootLayout;
    private ViewDragHelper mDragHelper;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
        mRootLayout = (RelativeLayout) inflater.inflate(R.layout.fragment_main, container, false);
        mRootLayout.setOnTouchListener(this);
        mDecor = (ImageView) mRootLayout.findViewById(R.id.decor);
        mBamboo = (ImageView) mRootLayout.findViewById(R.id.bamboo);
        mBackgroundBamboo = (ImageView) mRootLayout.findViewById(R.id.backround_bamboo);

        mDragHelper = ViewDragHelper.create(mRootLayout, 1.0f, new ViewDragHelper.Callback() {
            private final float MAX_LEFT = -0;
            private final float MAX_TOP = -20;
            private final float MAX_RIGHT = 50;
            private final float MAX_BOTTOM = 10;

            private final float MULTIPLIER = 0.1f;

            private final int DECOR_ELEVATION = 3;
            private final int FRONT_BAMBOO_ELEVATION = 6;
            private final int BACKGROUND_BAMBOO_ELEVATION = 1;

            private float mLeft = 0;
            private float mTop = 0;

            @Override
            public boolean tryCaptureView(View view, int i) {
                return true;
            }

            @Override
            public int clampViewPositionVertical(View child, int top, int dy) {
                mTop += dy * MULTIPLIER;
                mTop = mTop > MAX_BOTTOM ? MAX_BOTTOM : mTop < MAX_TOP ? MAX_TOP : mTop;

                mDecor.setTranslationY(mTop * DECOR_ELEVATION);
                mBamboo.setTranslationY(mTop * FRONT_BAMBOO_ELEVATION);
                mBackgroundBamboo.setTranslationY(mTop * BACKGROUND_BAMBOO_ELEVATION);
                return 0;
            }

            @Override
            public int clampViewPositionHorizontal(View child, int left, int dx) {
                mLeft += dx * MULTIPLIER;
                mLeft = mLeft < MAX_LEFT ? MAX_LEFT : mLeft > MAX_RIGHT ? MAX_RIGHT : mLeft;

                mDecor.setTranslationX(mLeft * DECOR_ELEVATION);
                mBamboo.setTranslationX(mLeft * FRONT_BAMBOO_ELEVATION);
                mBackgroundBamboo.setTranslationX(mLeft * BACKGROUND_BAMBOO_ELEVATION);
                return 0;
            }

            @Override
            public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy){
                mRootLayout.requestLayout();
            }
        });
        return mRootLayout;
    }



    @Override
    public boolean onTouch(View view, MotionEvent motionEvent) {
        mDragHelper.processTouchEvent(motionEvent);
        // you can still use this touch listener for buttons etc.
        return true;
    }
}

答案 6 :(得分:0)

嗨,您可以使用下面提供的ParallaxView类代码

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import java.util.ArrayList;

public class ParallaxView extends SurfaceView implements Runnable {

    private volatile boolean running;
    private Thread gameThread = null;

    // For drawing
    private Paint paint;
    private Canvas canvas;
    private SurfaceHolder ourHolder;

    // Holds a reference to the Activity
    Context context;

    // Control the fps
    long fps =60;

    // Screen resolution
    int screenWidth;
    int screenHeight;

    ParallaxView(Context context, int screenWidth, int screenHeight) {
        super(context);

        this.context = context;

        this.screenWidth = screenWidth;
        this.screenHeight = screenHeight;

        // Initialize our drawing objects
        ourHolder = getHolder();
        paint = new Paint();

    }

    @Override
    public void run() {

        while (running) {
            long startFrameTime = System.currentTimeMillis();

            update();

            draw();

            // Calculate the fps this frame
            long timeThisFrame = System.currentTimeMillis() - startFrameTime;
            if (timeThisFrame >= 1) {
                fps = 1000 / timeThisFrame;
            }
        }
    }

    private void update() {
        // Update all the background positions

    }

    private void draw() {

        if (ourHolder.getSurface().isValid()) {
            //First we lock the area of memory we will be drawing to
            canvas = ourHolder.lockCanvas();

            //draw a background color
            canvas.drawColor(Color.argb(255, 0, 3, 70));

            // Draw the background parallax

            // Draw the rest of the game
            paint.setTextSize(60);
            paint.setColor(Color.argb(255, 255, 255, 255));
            canvas.drawText("I am a plane", 350, screenHeight / 100 * 5, paint);
            paint.setTextSize(220);
            canvas.drawText("I'm a train", 50, screenHeight / 100*80, paint);

            // Draw the foreground parallax

            // Unlock and draw the scene
            ourHolder.unlockCanvasAndPost(canvas);
        }
    }

    // Clean up our thread if the game is stopped
    public void pause() {
        running = false;
        try {
            gameThread.join();
        } catch (InterruptedException e) {
            // Error
        }
    }

    // Make a new thread and start it
    // Execution moves to our run method
    public void resume() {
        running = true;
        gameThread = new Thread(this);
        gameThread.start();
    }

}// End of ParallaxView

要了解更多信息,可以去**

**:http://gamecodeschool.com/android/coding-a-parallax-scrolling-background-for-android/