版权声明:欢迎转载,转载请注明出处http://blog.csdn.net/qian_xiao_lj
实现两个ScrollView的同步显示。因为Android控件中没有此种功能,因此需要重写ScrollView。
public interface ScrollViewListener { void onScrollChanged(ObservableScrollView scrollView, int x, int y, int oldx, int oldy); }我们需要重写ScrollView才能实现该接口,因此有下面的代码(ObservableScrollView.java):
import android.content.Context; import android.util.AttributeSet; import android.widget.ScrollView; public class ObservableScrollView extends ScrollView { private ScrollViewListener scrollViewListener = null; public ObservableScrollView(Context context) { super(context); } public ObservableScrollView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } public ObservableScrollView(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); } } }接下来是界面的XML,这里是一个简单的Demo,如下(main.xml):
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="#ffffff" android:orientation="horizontal" > <com.devin.ObservableScrollView android:id="@+id/scrollview1" android:layout_width="400dp" android:layout_height="wrap_content" > <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" > <TextView android:layout_width="wrap_content" android:layout_height="200dp" android:layout_weight="1" android:text="monday" android:textColor="#000000" /> <TextView android:layout_width="wrap_content" android:layout_height="200dp" android:layout_weight="1" android:text="tuesday" android:textColor="#000000" /> <TextView android:layout_width="wrap_content" android:layout_height="200dp" android:layout_weight="1" android:text="wednesday" android:textColor="#000000" /> <TextView android:layout_width="wrap_content" android:layout_height="200dp" android:layout_weight="1" android:text="thursday" android:textColor="#000000" /> <TextView android:layout_width="wrap_content" android:layout_height="200dp" android:layout_weight="1" android:text="friday" android:textColor="#000000" /> <TextView android:layout_width="wrap_content" android:layout_height="200dp" android:layout_weight="1" android:text="saturday" android:textColor="#000000" /> <TextView android:layout_width="wrap_content" android:layout_height="200dp" android:layout_weight="1" android:text="sunday" android:textColor="#000000" /> </LinearLayout> </com.devin.ObservableScrollView> <com.devin.ObservableScrollView android:id="@+id/scrollview2" android:layout_width="400dp" android:layout_height="wrap_content" > <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" > <TextView android:layout_width="wrap_content" android:layout_height="200dp" android:layout_weight="1" android:text="monday" android:textColor="#000000" /> <TextView android:layout_width="wrap_content" android:layout_height="200dp" android:layout_weight="1" android:text="tuesday" android:textColor="#000000" /> <TextView android:layout_width="wrap_content" android:layout_height="200dp" android:layout_weight="1" android:text="wednesday" android:textColor="#000000" /> <TextView android:layout_width="wrap_content" android:layout_height="200dp" android:layout_weight="1" android:text="thursday" android:textColor="#000000" /> <TextView android:layout_width="wrap_content" android:layout_height="200dp" android:layout_weight="1" android:text="friday" android:textColor="#000000" /> <TextView android:layout_width="wrap_content" android:layout_height="200dp" android:layout_weight="1" android:text="saturday" android:textColor="#000000" /> <TextView android:layout_width="wrap_content" android:layout_height="200dp" android:layout_weight="1" android:text="sunday" android:textColor="#000000" /> </LinearLayout> </com.devin.ObservableScrollView> </LinearLayout>最后是我们的主程调用(TestActivity.java):
<strong style="font-size: 14px;">import android.app.Activity; import android.os.Bundle; public class TestActivity extends Activity implements ScrollViewListener { private ObservableScrollView scrollView1 = null; private ObservableScrollView scrollView2 = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); scrollView1 = (ObservableScrollView) findViewById(R.id.scrollview1); scrollView1.setScrollViewListener(this); scrollView2 = (ObservableScrollView) findViewById(R.id.scrollview2); scrollView2.setScrollViewListener(this); } public void onScrollChanged(ObservableScrollView scrollView, int x, int y, int oldx, int oldy) { if(scrollView == scrollView1) { scrollView2.scrollTo(x, y); } else if(scrollView == scrollView2) { scrollView1.scrollTo(x, y); } } } </strong><p style="font-size: 16px; font-weight: bold; margin-top: 0px; margin-bottom: 0.75em; line-height: 27.2000007629395px; text-indent: 1em; color: rgb(51, 51, 51); font-family: 'Helvetica Neue', Helvetica, Tahoma, Arial, STXihei, 'Microsoft YaHei', 微软雅黑, sans-serif; background-color: rgb(254, 254, 254);">可嵌套的<span style="line-height: 27.2000007629395px;">ScrollView:</span></p><p style="font-size: 16px; font-weight: bold; margin-top: 0px; margin-bottom: 0.75em; line-height: 27.2000007629395px; text-indent: 1em; font-family: 'Helvetica Neue', Helvetica, Tahoma, Arial, STXihei, 'Microsoft YaHei', 微软雅黑, sans-serif; background-color: rgb(254, 254, 254);"></p><p align="left" style="font-size: 14px;"><span style="color: rgb(68, 68, 68);">实现一个继承自ScrollView</span>的自定义控件,可以设置坐标,大小,并且能够任意添加其他的view。由于ScrollView只允许有一个子控件,所以,我们可以在其中加入一个ViewGroup,然后,将要添加的view加入该ViewGroup中即可</p><p align="left" style="font-size: 14px;">下面是该类的代码<span style="font-weight: bold;">:</span></p><p align="left" style="font-size: 14px; font-weight: bold;"></p><pre name="code" class="java" style="font-size: 14px; font-weight: bold;">public class LionScrollView extends ScrollView { private MainViewGroup mv; private int subViewWidth = 0; private int subViewHeight = 0; private int x; private int y; private int width; private int height; public LionScrollView() { super(MainView.mMainActivity); this.mv = new MainViewGroup(); super.addView(mv); } public void addView(View child) { if (child == null) return; this.mv.addView(child); } //This method should return false to intercept the touch event public boolean onInterceptTouchEvent(MotionEvent ev) { return false; } //here you can add some setters ..... protected void onLayout(boolean changed, int l, int t, int r, int b) { final int count = this.mv.getChildCount(); for (int i = 0; i < count; i++) { final View child = this.mv.getChildAt(i); int x = (int) child.getX() + child.getMeasuredWidth(); int y = (int) child.getY() + child.getMeasuredHeight(); if (x > subViewWidth) { subViewWidth = x; this.mv.setMinimumWidth(x); } if (y > subViewHeight) { subViewHeight = y; this.mv.setMinimumHeight(y); } } this.setLeft(this.x); this.setRight(this.x + this.width); this.setTop(this.y); this.setBottom(this.y + this.height); super.onLayout(changed, l, t, r, b); } }
横向ScrollView:
自定义Viewiw实现步骤:
1、继承要自定义View的类,并实现带有参数的构造方法
2、重写onMeasure(确定自定义View的大小)和onLayout(确定自定义View的位置)方法
关于HorizontalScrollView的滑动,我们可以用onScrollChanged来监听参数L:
打印日志时可以发现,当滚动条向左(画面向右滑动)的时候,L的值是逐渐增大的,所以我们可以通过它来作为动画的变化梯度值。
HorizontalScrollView.class
public class MyHorizontalScrollView extends HorizontalScrollView { // 在HorizontalScrollView有个LinearLayout private LinearLayout linearLayout; // 菜单,内容页 private ViewGroup myMenu; private ViewGroup myContent; //菜单宽度 private int myMenuWidth; // 屏幕宽度 private int screenWidth; // 菜单与屏幕右侧的距离(dp) private int myMenuPaddingRight = 50; // 避免多次调用onMeasure的标志 private boolean once = false; /** * 自定义View需要实现带有Context、AttributeSet这2个参数的构造方法,否则自定 义参数会出错 * 当使用了自定义属性时,会调用此构造方法 * * @param context * @param attrs */ public MyHorizontalScrollView(Context context, AttributeSet attrs) { super(context, attrs); // 获取屏幕宽度 WindowManager windowManager = (WindowManager) context .getSystemService(Context.WINDOW_SERVICE); DisplayMetrics outMetrics = new DisplayMetrics(); windowManager.getDefaultDisplay().getMetrics(outMetrics); screenWidth = outMetrics.widthPixels;// 屏幕宽度 // 将dp转换px myMenuPaddingRight = (int) TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP, 50, context.getResources() .getDisplayMetrics()); } /** * 设置子View的宽高,决定自身View的宽高,每次启动都会调用此方法 */ @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); if (!once) {//使其只调用一次 // this指的是HorizontalScrollView,获取各个元素 linearLayout = (LinearLayout) this.getChildAt(0);// 第一个子元素 myMenu = (ViewGroup) linearLayout.getChildAt(0);// HorizontalScrollView下LinearLayout的第一个子元素 myContent = (ViewGroup) linearLayout.getChildAt(1);// HorizontalScrollView下LinearLayout的第二个子元素 // 设置子View的宽高,高于屏幕一致 myMenuWidth=myMenu.getLayoutParams().width = screenWidth - myMenuPaddingRight;// 菜单的宽度=屏幕宽度-右边距 myContent.getLayoutParams().width = screenWidth;// 内容宽度=屏幕宽度 // 决定自身View的宽高,高于屏幕一致 // 由于这里的LinearLayout里只包含了Menu和Content所以就不需要额外的去指定自身的宽 once = true; } } //设置View的位置,首先,先将Menu隐藏(在eclipse中ScrollView的画面内容(非滚动条)正数表示向左移,向上移) @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { super.onLayout(changed, l, t, r, b); //刚载入界面的时候隐藏Menu菜单也就是ScrollView向左滑动菜单自身的大小 if(changed){ this.scrollTo(myMenuWidth, 0);//向左滑动,相当于把右边的内容页拖到正中央,菜单隐藏 } } @Override public boolean onTouchEvent(MotionEvent ev) { int action=ev.getAction(); switch (action) { case MotionEvent.ACTION_UP: int scrollX=this.getScrollX();//滑动的距离scrollTo方法里,也就是onMeasure方法里的向左滑动那部分 if(scrollX>=myMenuWidth/2){ this.smoothScrollTo(myMenuWidth,0);//向左滑动展示内容 }else{ this.smoothScrollTo(0, 0); } return true; } return super.onTouchEvent(ev); } @Override protected void onScrollChanged(int l, int t, int oldl, int oldt) { super.onScrollChanged(l, t, oldl, oldt); Log.i("tuzi",l+""); float scale = l * 1.0f / myMenuWidth; // 1 ~ 0 /** * 区别1:内容区域1.0~0.7 缩放的效果 scale : 1.0~0.0 0.7 + 0.3 * scale * * 区别2:菜单的偏移量需要修改 * * 区别3:菜单的显示时有缩放以及透明度变化 缩放:0.7 ~1.0 1.0 - scale * 0.3 透明度 0.6 ~ 1.0 * 0.6+ 0.4 * (1- scale) ; * */ float rightScale = 0.7f + 0.3f * scale; float leftScale = 1.0f - scale * 0.3f; float leftAlpha = 0.6f + 0.4f * (1 - scale); // 调用属性动画,设置TranslationX ViewHelper.setTranslationX(myMenu, myMenuWidth * scale * 0.8f); ViewHelper.setScaleX(myMenu, leftScale); ViewHelper.setScaleY(myMenu, leftScale); ViewHelper.setAlpha(myMenu, leftAlpha); // 设置content的缩放的中心点 ViewHelper.setPivotX(myContent, 0); ViewHelper.setPivotY(myContent, myContent.getHeight() / 2); ViewHelper.setScaleX(myContent, rightScale); ViewHelper.setScaleY(myContent, rightScale); } }