开发一个Android主屏幕屏幕、Android

2023-09-12 21:36:46 作者:心软是吃软糖软化的

我工作的一个应用程序,有一个主屏幕。这个主屏幕应该表现得像在的Andr​​oid主屏幕在这里你可以几个视图之间通过扔你的手指在触摸屏切换。

I am working on an app that has a homescreen. This homescreen should behave like the android homescreen where you can switch between several views by flinging your finger over the touch screen.

的溶液是容易的。我已 3视图实例,右键的离开和当前视图的。我从这个实例中的 viewflipper 我之前进行初始化。因为我有一个HTC G1我筛网是320像素宽,480像素高。

The solution is easy. I have 3 view instances, right, left and current view. I get this instances from the viewflipper that I initialized earlier. Since I have a HTC G1 my sreen is 320 px in width and 480 px in height.

想象一下,你捕捉上下运动事件行动的向下价值,当你触摸屏幕。然后你移动你的手指在屏幕应该完全相同的方式,所以你必须重新计算视图的位置移动。它的工作对我来说,到目前为止,但我现在面临一个奇怪的问题。当你触摸右视图不动你的手指,但保持它在屏幕上超过一秒的视图中消失,显示左视图。

Imagine you capture the down value of a action down motion event when you touch the screen. Then you move your finger and the screen should move in exactly the same way so you have to recalculate the view's position. It works for me so far but I am facing a strange problem. When you touch the right view without moving you finger but keeping it on the screen for less then a second the view disappears and shows the left view.

下面是我的code:

public class MainActivity extends Activity implements OnTouchListener{

    private ViewFlipper vf;
    private float downXValue;
    private View view1, view2, view3;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        this.vf = (ViewFlipper) findViewById(R.id.flipper);

        if(this.vf != null){
             this.view1 = vf.getChildAt(0);
             this.view2 = vf.getChildAt(1);  
             this.view3 = vf.getChildAt(2);
             vf.setDisplayedChild(0);
         }      

         LinearLayout layMain = (LinearLayout) findViewById(R.id.layout_main);
         layMain.setOnTouchListener((OnTouchListener) this);
    }

    public boolean onTouch(View v, MotionEvent arg1) {

         final View currentView = vf.getCurrentView();
         final View leftView, rightView;

         if(currentView == view1){
             leftView = view3;
             rightView = view2;
         }else if(currentView == view2){
             leftView = view1;
             rightView = view3;
         }else if(currentView == view3){
             leftView = view2;
             rightView = view1;
         }else{
             leftView = null;
             rightView = null;
         }

         switch (arg1.getAction()){
            case MotionEvent.ACTION_DOWN:{
                this.downXValue = arg1.getX();
                break;
            }
            case MotionEvent.ACTION_UP:{
                float currentX = arg1.getX();            
                    if ((downXValue < currentX)){
                        if(currentView != view3){
                        float t3 = (320-(currentX-downXValue))/320;                             
                        this.vf.setInAnimation(AnimationHelper.inFromLeftAnimation(t3));
                        this.vf.setOutAnimation(AnimationHelper.outToRightAnimation(t3));
                        this.vf.showPrevious(); } 
                      }

                    if ((downXValue > currentX)){
                        if(currentView != view2){
                        float t = (320-(downXValue-currentX))/320;
                        this.vf.setInAnimation(AnimationHelper.inFromRightAnimation(t));
                        this.vf.setOutAnimation(AnimationHelper.outToLeftAnimation(t));
                        this.vf.showNext();}    
                    }                         
            }
            break;
            case MotionEvent.ACTION_MOVE:{

                leftView.setVisibility(View.VISIBLE);
                rightView.setVisibility(View.VISIBLE);

                float currentX = arg1.getX();     
                if(downXValue > currentX){  
                    if(currentView != view2){
                        currentView.layout((int) (currentX - downXValue),
                        currentView.getTop(),
                        (int) (currentX - downXValue) + 320,
                        currentView.getBottom()); 
                    }
                }

                if(downXValue < currentX){  
                    if(currentView != view3){
                        currentView.layout((int) (currentX - downXValue),
                        currentView.getTop(),
                        (int) (currentX - downXValue) + 320,
                        currentView.getBottom());


                    }
                }
                leftView.layout(currentView.getLeft()-320, leftView.getTop(),
                       currentView.getLeft(), leftView.getBottom());   

                rightView.layout(currentView.getRight(), rightView.getTop(), 
                        currentView.getRight() + 320, rightView.getBottom());
                }
            }

        return true;
    }

    public static class AnimationHelper {
          public static Animation inFromRightAnimation(float param) {
            Animation inFromRight = new TranslateAnimation(
            Animation.RELATIVE_TO_PARENT, +param,
            Animation.RELATIVE_TO_PARENT, 0.0f,
            Animation.RELATIVE_TO_PARENT, 0.0f,
            Animation.RELATIVE_TO_PARENT, 0.0f);
            inFromRight.setDuration(250);
            inFromRight.setInterpolator(new AccelerateInterpolator());
            return inFromRight;
          }

          public static Animation outToLeftAnimation(float param) {
            Animation outtoLeft = new TranslateAnimation(
            Animation.RELATIVE_TO_PARENT, 0.0f,
            Animation.RELATIVE_TO_PARENT, -param,
            Animation.RELATIVE_TO_PARENT, 0.0f,
            Animation.RELATIVE_TO_PARENT, 0.0f);
            outtoLeft.setDuration(250);
            outtoLeft.setInterpolator(new AccelerateInterpolator());
            return outtoLeft;
          }

          // for the next movement
          public static Animation inFromLeftAnimation(float param) {
            Animation inFromLeft = new TranslateAnimation(
            Animation.RELATIVE_TO_PARENT, -param,
            Animation.RELATIVE_TO_PARENT, 0.0f,
            Animation.RELATIVE_TO_PARENT, 0.0f,
            Animation.RELATIVE_TO_PARENT, 0.0f);
            inFromLeft.setDuration(250);
            inFromLeft.setInterpolator(new AccelerateInterpolator());
            return inFromLeft;
          }

          public static Animation outToRightAnimation(float param) {
            Animation outtoRight = new TranslateAnimation(
            Animation.RELATIVE_TO_PARENT, 0.0f,
            Animation.RELATIVE_TO_PARENT, +param,
            Animation.RELATIVE_TO_PARENT, 0.0f,
            Animation.RELATIVE_TO_PARENT, 0.0f);
            outtoRight.setDuration(250);
            outtoRight.setInterpolator(new AccelerateInterpolator());
            return outtoRight;
          }
        }

}

我觉得这样的主屏幕是一个有趣的UI元素。

I think such a Homescreen is an interesting UI element.

任何想法?

您可以在这里下载工作Eclipse项目: HTTP:// WWW .megaupload.com / D = 3M3IYGGM

推荐答案

修改(2012年7月3日):

EDIT (July 3rd, 2012):

由于似乎仍对这个答案相当多的观点和意见,我想我应该加一个音符,与较新的SDK,你现在应该使用的 ViewPager 而是具有相同的功能。这个类也包含在 Android的支持库这样你就可以还用它来在早期的Andr​​oid设备上运行。

Since there seem to be still quite a few views and comments about this answer, I thought I should add a note, that with the newer SDK, you should now use ViewPager instead to have the same functionality. That class is also included in the Android Support library so you can also use it to run on earlier Android devices.

修改(2013年3月4日):

EDIT (March 4th, 2013):

由于还有人来这里,就是想也说,我把一个ViewPager与背景在移动较慢的速度给视差效果。在code是这里。

Since there are still people coming here, just wanted to also say I put together a ViewPager with the background moving at slower speed to give a parallax effect. The code is here.

如果你真的想手工做这一切,原来答案就在这里低于...

If you really want to do it all manually, the original answer is here below...

我认为你可以找到你所寻找的东西在这里:的http:// www.anddev.org/why_do_not_these_$​​c$cs_work-t4012.html

I think you can find what you are looking for here : http://www.anddev.org/why_do_not_these_codes_work-t4012.html

我曾经在不同的项目中也创建具有不同意见的主屏幕。这是直接从Android启动,它工作得很好下面的跟帖。

I used that in a different project to also create a home screen with different views. This is straight from the Android Launcher, it works quite well after following that thread.

下面是我的code ...第一源$ C ​​$ C

Here is my code... first the source code

package com.matthieu.launcher;

import android.content.Context;
import android.util.Log;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewConfiguration;
import android.widget.Scroller;

public class DragableSpace extends ViewGroup {
    private Scroller mScroller;
    private VelocityTracker mVelocityTracker;

    private int mScrollX = 0;
    private int mCurrentScreen = 0;

    private float mLastMotionX;

    private static final String LOG_TAG = "DragableSpace";

    private static final int SNAP_VELOCITY = 1000;

    private final static int TOUCH_STATE_REST = 0;
    private final static int TOUCH_STATE_SCROLLING = 1;

    private int mTouchState = TOUCH_STATE_REST;

    private int mTouchSlop = 0;

    public DragableSpace(Context context) {
        super(context);
        mScroller = new Scroller(context);

        mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();

        this.setLayoutParams(new ViewGroup.LayoutParams(
                    ViewGroup.LayoutParams.WRAP_CONTENT,
                    ViewGroup.LayoutParams.FILL_PARENT));
    }

    public DragableSpace(Context context, AttributeSet attrs) {
        super(context, attrs);
        mScroller = new Scroller(context);

        mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();

        this.setLayoutParams(new ViewGroup.LayoutParams(
                    ViewGroup.LayoutParams.WRAP_CONTENT ,
                    ViewGroup.LayoutParams.FILL_PARENT));

        TypedArray a=getContext().obtainStyledAttributes(attrs,R.styleable.DragableSpace);
        mCurrentScreen = a.getInteger(R.styleable.DragableSpace_default_screen, 0);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        /*
         * This method JUST determines whether we want to intercept the motion.
         * If we return true, onTouchEvent will be called and we do the actual
         * scrolling there.
         */

        /*
         * Shortcut the most recurring case: the user is in the dragging state
         * and he is moving his finger. We want to intercept this motion.
         */
        final int action = ev.getAction();
        if ((action == MotionEvent.ACTION_MOVE)
                && (mTouchState != TOUCH_STATE_REST)) {
            return true;
                }

        final float x = ev.getX();

        switch (action) {
            case MotionEvent.ACTION_MOVE:
                /*
                 * mIsBeingDragged == false, otherwise the shortcut would have caught it. Check
                 * whether the user has moved far enough from his original down touch.
                 */

                /*
                 * Locally do absolute value. mLastMotionX is set to the y value
                 * of the down event.
                 */
                final int xDiff = (int) Math.abs(x - mLastMotionX);

                boolean xMoved = xDiff > mTouchSlop;

                if (xMoved) {
                    // Scroll if the user moved far enough along the X axis
                    mTouchState = TOUCH_STATE_SCROLLING;
                }
                break;

            case MotionEvent.ACTION_DOWN:
                // Remember location of down touch
                mLastMotionX = x;

                /*
                 * If being flinged and user touches the screen, initiate drag;
                 * otherwise don't.  mScroller.isFinished should be false when
                 * being flinged.
                 */
                mTouchState = mScroller.isFinished() ? TOUCH_STATE_REST : TOUCH_STATE_SCROLLING;
                break;

            case MotionEvent.ACTION_CANCEL:
            case MotionEvent.ACTION_UP:
                // Release the drag
                mTouchState = TOUCH_STATE_REST;
                break;
        }

        /*
         * The only time we want to intercept motion events is if we are in the
         * drag mode.
         */
        return mTouchState != TOUCH_STATE_REST;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {

        if (mVelocityTracker == null) {
            mVelocityTracker = VelocityTracker.obtain();
        }
        mVelocityTracker.addMovement(event);

        final int action = event.getAction();
        final float x = event.getX();

        switch (action) {
            case MotionEvent.ACTION_DOWN:
                Log.i(LOG_TAG, "event : down");
                /*
                 * If being flinged and user touches, stop the fling. isFinished
                 * will be false if being flinged.
                 */
                if (!mScroller.isFinished()) {
                    mScroller.abortAnimation();
                }

                // Remember where the motion event started
                mLastMotionX = x;
                break;
            case MotionEvent.ACTION_MOVE:
                // Log.i(LOG_TAG,"event : move");
                // if (mTouchState == TOUCH_STATE_SCROLLING) {
                // Scroll to follow the motion event
                final int deltaX = (int) (mLastMotionX - x);
                mLastMotionX = x;

                //Log.i(LOG_TAG, "event : move, deltaX " + deltaX + ", mScrollX " + mScrollX);

                if (deltaX < 0) {
                    if (mScrollX > 0) {
                        scrollBy(Math.max(-mScrollX, deltaX), 0);
                    }
                } else if (deltaX > 0) {
                    final int availableToScroll = getChildAt(getChildCount() - 1)
                        .getRight()
                        - mScrollX - getWidth();
                    if (availableToScroll > 0) {
                        scrollBy(Math.min(availableToScroll, deltaX), 0);
                    }
                }
                // }
                break;
            case MotionEvent.ACTION_UP:
                Log.i(LOG_TAG, "event : up");
                // if (mTouchState == TOUCH_STATE_SCROLLING) {
                final VelocityTracker velocityTracker = mVelocityTracker;
                velocityTracker.computeCurrentVelocity(1000);
                int velocityX = (int) velocityTracker.getXVelocity();

                if (velocityX > SNAP_VELOCITY && mCurrentScreen > 0) {
                    // Fling hard enough to move left
                    snapToScreen(mCurrentScreen - 1);
                } else if (velocityX < -SNAP_VELOCITY
                        && mCurrentScreen < getChildCount() - 1) {
                    // Fling hard enough to move right
                    snapToScreen(mCurrentScreen + 1);
                } else {
                    snapToDestination();
                }

                if (mVelocityTracker != null) {
                    mVelocityTracker.recycle();
                    mVelocityTracker = null;
                }
                // }
                mTouchState = TOUCH_STATE_REST;
                break;
            case MotionEvent.ACTION_CANCEL:
                Log.i(LOG_TAG, "event : cancel");
                mTouchState = TOUCH_STATE_REST;
        }
        mScrollX = this.getScrollX();

        return true;
    }

    private void snapToDestination() {
        final int screenWidth = getWidth();
        final int whichScreen = (mScrollX + (screenWidth / 2)) / screenWidth;
        Log.i(LOG_TAG, "from des");
        snapToScreen(whichScreen);
    }

    public void snapToScreen(int whichScreen) {         
        Log.i(LOG_TAG, "snap To Screen " + whichScreen);
        mCurrentScreen = whichScreen;
        final int newX = whichScreen * getWidth();
        final int delta = newX - mScrollX;
        mScroller.startScroll(mScrollX, 0, delta, 0, Math.abs(delta) * 2);             
        invalidate();
    }

    public void setToScreen(int whichScreen) {
        Log.i(LOG_TAG, "set To Screen " + whichScreen);
        mCurrentScreen = whichScreen;
        final int newX = whichScreen * getWidth();
        mScroller.startScroll(newX, 0, 0, 0, 10);             
        invalidate();
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        int childLeft = 0;

        final int count = getChildCount();
        for (int i = 0; i < count; i++) {
            final View child = getChildAt(i);
            if (child.getVisibility() != View.GONE) {
                final int childWidth = child.getMeasuredWidth();
                child.layout(childLeft, 0, childLeft + childWidth, child
                        .getMeasuredHeight());
                childLeft += childWidth;
            }
        }

    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        final int width = MeasureSpec.getSize(widthMeasureSpec);
        final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        if (widthMode != MeasureSpec.EXACTLY) {
            throw new IllegalStateException("error mode.");
        }

        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        if (heightMode != MeasureSpec.EXACTLY) {
            throw new IllegalStateException("error mode.");
        }

        // The children are given the same width and height as the workspace
        final int count = getChildCount();
        for (int i = 0; i < count; i++) {
            getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec);
        }
        Log.i(LOG_TAG, "moving to screen "+mCurrentScreen);
        scrollTo(mCurrentScreen * width, 0);      
    }  

    @Override
    public void computeScroll() {
        if (mScroller.computeScrollOffset()) {
            mScrollX = mScroller.getCurrX();
            scrollTo(mScrollX, 0);
            postInvalidate();
        }
    }
}

和布局文件:

<?xml version="1.0" encoding="utf-8"?>
<com.matthieu.launcher.DragableSpace xmlns:app="http://schemas.android.com/apk/res/com.matthieu.launcher"
    xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/space"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
app:default_screen="1"
>
<include android:id="@+id/left"  layout="@layout/left_screen" />
<include android:id="@+id/center"  layout="@layout/initial_screen" />
<include android:id="@+id/right"  layout="@layout/right_screen" />
</com.matthieu.launcher.DragableSpace>

要能有在XML文件中的附加属性,要保存这RES /价值/ attrs.xml

To be able to have the extra attribute in the xml file, you want to save this in res/values/attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="DragableSpace">
        <attr name="default_screen" format="integer"/>
    </declare-styleable>
</resources>