android horizontalscrollbarView 左右移动之后,子控件view 坐标与移动前的坐标不变。

Android之重写ScrollView实现两个ScrollView的同步滚动显示
1.背景介绍
  最近项目用到两个ScrollView的同步显示,即拖动左边的ScrollView滚动的同时,实现右边的ScrollView同步滚动。此种情形常用在复杂界面布局中,比如左边的ScrollView显示主要项目,只需上下滚动即可;右边项目是次要项目,可以实现上下或者左右滚动,当上下滚动时,需要左右两边的同步显示。
& & & & &如图所示,左侧是主项目(日期和股票代码),右侧是次要项目(开盘价、最高价、成交量....等等信息)。因为信息比较多,左侧的主项目需要上下拖动显示,而右侧则需要上下左右都可以拖动才能显示完全(ScrollView嵌套一个HorizontalScrollView)。我们希望左侧或右侧上下拖动时,能够实现同步。这就需要实现两个ScrollView的同步显示。因为控件中没有此种功能,因此需要重写ScrollView。
2.思路介绍
  我们首先想到使用ScrollView的类似与setOnScrollChangedListener的方法来实现,当一个ScrollView滚动时,触发该方法进而使另外一个ScrollView滚动。不过很遗憾,谷歌没有提供该方法。通过查询相应的源代码,我们发现该方法的原型
protected void onScrollChanged(int x, int y, int oldx, int oldy) &
该方法是protected类型,不能直接调用,于是需要重新实现ScrollView。
3.具体实现
  首先,定一个一个接口(ScrollViewListener.java):
public interface ScrollViewListener { &
& & void onScrollChanged(ObservableScrollView scrollView, int x, int y, int oldx, int oldy); &
我们需要重写ScrollView才能实现该借口,因此有下面的代码(ObservableScrollView.java):
package com. &
import android.content.C &
import android.util.AttributeS &
import android.widget.ScrollV &
public class ObservableScrollView extends ScrollView { &
& & private ScrollViewListener scrollViewListener = &
& & 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 = scrollViewL &
& & @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=&/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& &
最后是我们的主程调用(PadTestActivity.java):
package com. &
import android.app.A &
import android.os.B &
public class PadTestActivity extends Activity implements ScrollViewListener { &
& & private ObservableScrollView scrollView1 = &
& & private ObservableScrollView scrollView2 = &
& & @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); &
& & & & } &
(window.slotbydup=window.slotbydup || []).push({
id: '2467140',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467141',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467143',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467148',
container: s,
size: '1000,90',
display: 'inlay-fix'二次元同好交流新大陆
扫码下载App
汇聚2000万达人的兴趣社区下载即送20张免费照片冲印
扫码下载App
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!&&|&&
LOFTER精选
网易考拉推荐
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
阅读(1786)|
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
历史上的今天
在LOFTER的更多文章
loftPermalink:'',
id:'fks_',
blogTitle:'android.view.View',
blogAbstract:'View很重要,很多控件都继承自它
  一、结构
    java.lang.Object      android.view.View
    已知直接子类:
       AnalogClock, ImageView, KeyboardView, ProgressBar, SurfaceView, TextView, ViewGroup, ViewStub
    已知间接子类:
      AbsListView, AbsSeekBar, AbsSpinner, AbsoluteLayout, AdapterView&T extends Adapter&, AppWidgetHostView, AutoCompleteTextView, Button, CheckBox, CheckedTextView, Chronometer,',
blogTag:'',
blogUrl:'blog/static/',
isPublished:1,
istop:false,
modifyTime:3,
publishTime:0,
permalink:'blog/static/',
commentCount:0,
mainCommentCount:0,
recommendCount:1,
bsrk:-100,
publisherId:0,
recomBlogHome:false,
currentRecomBlog:false,
attachmentsFileIds:[],
groupInfo:{},
friendstatus:'none',
followstatus:'unFollow',
pubSucc:'',
visitorProvince:'',
visitorCity:'',
visitorNewUser:false,
postAddInfo:{},
mset:'000',
remindgoodnightblog:false,
isBlackVisitor:false,
isShowYodaoAd:false,
hostIntro:'',
hmcon:'0',
selfRecomBlogCount:'0',
lofter_single:''
{list a as x}
{if x.moveFrom=='wap'}
{elseif x.moveFrom=='iphone'}
{elseif x.moveFrom=='android'}
{elseif x.moveFrom=='mobile'}
${a.selfIntro|escape}{if great260}${suplement}{/if}
{list a as x}
推荐过这篇日志的人:
{list a as x}
{if !!b&&b.length>0}
他们还推荐了:
{list b as y}
转载记录:
{list d as x}
{list a as x}
{list a as x}
{list a as x}
{list a as x}
{if x_index>4}{break}{/if}
${fn2(x.publishTime,'yyyy-MM-dd HH:mm:ss')}
{list a as x}
{if !!(blogDetail.preBlogPermalink)}
{if !!(blogDetail.nextBlogPermalink)}
{list a as x}
{if defined('newslist')&&newslist.length>0}
{list newslist as x}
{if x_index>7}{break}{/if}
{list a as x}
{var first_option =}
{list x.voteDetailList as voteToOption}
{if voteToOption==1}
{if first_option==false},{/if}&&“${b[voteToOption_index]}”&&
{if (x.role!="-1") },“我是${c[x.role]}”&&{/if}
&&&&&&&&${fn1(x.voteTime)}
{if x.userName==''}{/if}
网易公司版权所有&&
{list x.l as y}
{if defined('wl')}
{list wl as x}{/list}  这是一个很简单的功能,作为新手,做一下笔记。也给其它有需要的人提供一个参考。
  首先HorizontalScrollView都知道用途了。它可以实现类似&桌面程序&左右切换页的效果。一般情况下里面的页数都是固定的,但是也有可能遇到不固定页数的,比如动态加载照片,或者像我这次需要实现的情况。
  实现功能:实现日历的&日视图&。一页表示某一天的情况,向右翻页可翻到下一天,向左翻到上一天。而且可以随意翻到任意一天。每一页记录有当天的待办事项(这个就另外写了,这里只实现无限左右翻页)。
  由于每天作为一页,把所有天数都加载到ScrollView中是不现实的。考虑到占用问题,ScrollView中肯定不要放太多东西的好。所以只放3页。如下图所示:
  HorizontalScrollView中仅有3页。在第0页,向左翻的时候,松手的一瞬间,1页消失,-2页加载,然后smoothScroll到 -1页。向右亦然。因此可以保证不占用过多内存,又可以无限翻页。
  实现的时候还遇到一点小问题,顺便也一起写下来。
  一开始我很自然地想到重写HorizontalScrollView。即代码中的KamHorizontalScrollView。
主要是重写onTouchEvent方法,用于处理用户手指事件。
由于每个子View占一屏,不可以出现两个View各占一半的现象,需要有一个将子View分页化的方法。在我的代码中就是public boolean scrollToPage(int);该方法传入的是页码,可以保证滑动到正确的位置,而不会滑一半。
还有一点要注意,翻页的时候,为了保证ScrollView只有3页,需要增加删除子View。在末尾增删没有问题,但在首部增加,所有的子View会向后移动,在首部删除,所有的子View会向前移动,因此这两个操作需要立即改变ScrollView的scroll值以保证屏幕显示顺滑。这一点在方法public boolean addLeft(View);和public boolean removeLeft();中均有体现。
  接下来是我过程中出现的:
  1、重写HorizontalScrollView后,我在中进行初始化,添加三个初始的子View,报错。
  解决:构造函数调用的时候,ScrollView还没有实例化,因此这个时候不能添加子View。应该等实例化之后再添加。重写protected void onFinishInflate();方法即可得到实例化完成的时机,在该方法下初始化。
  2、左右滑动的时候,我调用的是scrollToPage(1);但是总是滑动到第2页或第0页。就是不能定在第1页。
  解决:这个问题我花了不少时间(其实如果我去认真看看API就能很快搞定的)。通过Log,addView之后,新的View的Left值仍是0。或者说addView之后的一瞬间,layout中的所有子View还是保持原有的状态。过了一阵子才又重新排列的。所以我需要获得重新排列的时机,才能scroll到正确位置。之前写JavaSE的布局有重写过排列布局的方法,所以这个也有。说白了就是onLayout方法(我以为是onMeasure,试了不行很纠结)。onLayout方法中,应该就是对所有子View进行重新排列了。(这一点可以自己去试试,先addView,然后立刻获取刚才这个View的位置和尺寸,会发现都是0。然后你可以通过按键事件再获取一次,会发现得到正确值了。因为从addView到按键这段时间足够他重新排列了。)
  所以通过LinearLayout.addOnLayoutChangeListener(listener);就可以重新排列的时机。但是该方法需要APILevel 11及以上。刚好我在用我的G12测试,APILevel10。虽然很纠结,我也只能重写了LinearLayout,即代码中的KamLinearLayout,还有自定义监听器kamLayoutChangeListener。重写仅仅是为了在Android2.3监听onLayout。
  另外加了一点小细节,翻页的机制除了手指滑动的距离,还有手指滑动的速度。自己写的SpeedChange三个方法。测试了一下感觉效果挺不错。
  最后把源码附上,写了比较详细的,希望能帮助到初学者。不要像我走太多弯路。(注意改包名)
KamHorizontalScrollView.java
1 package com.kam.horizontalscrollviewtest.
3 import com.kam.horizontalscrollviewtest.R;
5 import android.content.C
6 import android.graphics.C
7 import android.util.AttributeS
8 import android.util.DisplayM
9 import android.util.L
10 import android.view.G
11 import android.view.MotionE
12 import android.view.V
13 import android.view.ViewG
14 import android.widget.HorizontalScrollV
15 import android.widget.LinearL
16 import android.widget.TextV
17 import android.widget.FrameLayout.LayoutP
18 /*如果不需要支持Android2.3,可以将代码中所有KamLinearLayout替换为ViewGroup*/
KamHorizontalScrollView extends HorizontalScrollView {
private static String tag = "KamHorizontalScrollView";
/*记录当前的页数标识(做日视图的时候可以和该值今日的日期作差)*/
private int PageNo=0;
/*保存ScrollView中的ViewGroup,如果不需要支持Android2.3,可以将KamLinearLayout替换为ViewGroup*/
private KamLinearLayout childGroup = null;
/*这是判断左右滑动用的(个人喜好,其实不需要这么麻烦)*/
private int poscache[] = new int[4];
private int
public KamHorizontalScrollView(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
this.context=
public KamHorizontalScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
this.context=
public KamHorizontalScrollView(Context context) {
super(context);
// TODO Auto-generated constructor stub
this.context=
/*重写触摸事件,判断左右滑动*/
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
startpos = (int) ev.getX();
/*用于判断触摸滑动的速度*/
initSpeedChange((int) ev.getX());
case MotionEvent.ACTION_MOVE: {
/*更新触摸速度信息*/
movingSpeedChange((int) ev.getX());
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL: {
/*先根据速度来判断向左或向右*/
int speed = releaseSpeedChange((int) ev.getX());
if(speed&0){
nextPage();
return true;
if(speed&0){
prevPage();
return true;
/*这里是根据触摸起始和结束位置来判断向左或向右*/
if (Math.abs((ev.getX() - startpos)) & getWidth() / 4) {
if (ev.getX() - startpos & 0) {
prevPage();
nextPage();
scrollToPage(1);
return true;
return super.onTouchEvent(ev);
/*完成实例化*/
protected void onFinishInflate(){
super.onFinishInflate();
Log.i(tag, "onFinishInflate Called!");
/*初始化,加入三个子View*/
private void init(){
this.childGroup=(KamLinearLayout) findViewById(R.id.container);
/*添加LayoutChange监听器*/
childGroup.addKamLayoutChangeListener(listener);
/*调用其自身的LayoutChange监听器(不支持Android2.3)*/
/*childGroup.addOnLayoutChangeListener(listener);*/
addRight(createExampleView(-1));
addRight(createExampleView(0));
addRight(createExampleView(1));
/*添加监听器*/
kamLayoutChangeListener listener = new kamLayoutChangeListener() {
public void onLayoutChange() {
// TODO Auto-generated method stub
Log.i(tag, "onLayoutChanged Called!");
scrollToPage(1);
//注意,如果不需要支持Android2.3,可以将上面的listener替换成下方listener
OnLayoutChangeListener listener = new OnLayoutChangeListener() {
public void onLayoutChange(View arg0, int arg1, int arg2, int arg3,
int arg4, int arg5, int arg6, int arg7, int arg8) {
// TODO Auto-generated method stub
Log.i(tag, "onLayoutChanged Called!");
scrollToPage(1);
/*左翻页*/
public void prevPage(){
addLeft(createExampleView(PageNo-1));
removeRight();
/*右翻页*/
public void nextPage(){
addRight(createExampleView(PageNo+1));
removeLeft();
/*获取某个孩子的X坐标*/
private int getChildLeft(int index){
if (index&=0 && childGroup != null) {
if(index& childGroup.getChildCount())
childGroup.getChildAt(index).getLeft();
* 向右边添加View
* @param view 需要添加的View
* @return true添加成功|false添加失败
public boolean addRight(View view){
if(view==null || childGroup==null)return false;
childGroup.addView(view);
return true;
* 删除右边的View
* @return true成功|false失败
public boolean removeRight(){
if( childGroup==null || childGroup.getChildCount()&=0)return false;
childGroup.removeViewAt(childGroup.getChildCount()-1);
return true;
* 向左边添加View
* @param view 需要添加的View
* @return true添加成功|false添加失败
public boolean addLeft(View view){
if(view==null || childGroup==null)return false;
childGroup.addView(view, 0);
/*因为在左边增加了View,因此所有View的x坐标都会增加,因此需要让ScrollView也跟着移动,才能从屏幕看来保持平滑。*/
int tmpwidth = view.getLayoutParams().
if(tmpwidth==0)tmpwidth=getWinWidth();
Log.i(tag, "the new view's width = "+view.getLayoutParams().width);
this.scrollTo(this.getScrollX()+tmpwidth, 0);
return true;
* 删除左边的View
* @return true成功|false失败
public boolean removeLeft(){
if( childGroup==null || childGroup.getChildCount()&=0)return false;
/*因为在左边删除了View,因此所有View的x坐标都会减少,因此需要让ScrollView也跟着移动。*/
int tmpwidth=childGroup.getChildAt(0).getWidth();
childGroup.removeViewAt(0);
this.scrollTo((int) (this.getScrollX()-tmpwidth), 0);
return true;
* 跳转到指定的页面
* @param index 跳转的页码
public boolean scrollToPage(int index){
if(childGroup==null)return false;
if(index&0 || index &= childGroup.getChildCount())return false;
smoothScrollTo(getChildLeft(index), 0);
return true;
private int getWinWidth() {
DisplayMetrics dm = new DisplayMetrics();
// 获取屏幕信息
dm = context.getResources().getDisplayMetrics();
return dm.widthP
private int getWinHeight() {
DisplayMetrics dm = new DisplayMetrics();
// 获取屏幕信息
dm = context.getResources().getDisplayMetrics();
return dm.heightP
/*生成一个测试用View。真正使用的时候就不需要这个了。*/
private View createExampleView(int index){
LayoutParams params = new LayoutParams(getWinWidth(), getWinHeight());
/*设置不同的背景色使效果更加明显*/
int colorarr[] = {
Color.rgb(240, 180, 180),
Color.rgb(240, 240, 180),
Color.rgb(180, 240, 240),
Color.rgb(180, 240, 180)};
TextView txtview = new TextView(context);
txtview.setBackgroundColor(colorarr[(index%4+4) % 4]);
txtview.setText(index + "");
txtview.setTextSize(40);
txtview.setGravity(Gravity.CENTER);
txtview.setLayoutParams(params);
/*下面的方法仅仅是个人喜好加上的,用于判断用户手指左右滑动的速度。*/
private void initSpeedChange(int x){
if(poscache.length&=1)return;
poscache[0]=1;
for(int i=1;i&poscache.i++){
private void movingSpeedChange(int x){
poscache[0]%=poscache.length-1;
poscache[0]++;
//Log.i(tag, " speed:"+(x-poscache[poscache[0]]));
poscache[poscache[0]]=x;
private int releaseSpeedChange(int x){
return releaseSpeedChange(x, 30);
private int releaseSpeedChange(int x,int limit){
poscache[0]%=poscache.length-1;
poscache[0]++;
/*检测到向左的速度很大*/
if(poscache[poscache[0]]-x&limit)return 1;
/*检测到向右的速度很大*/
if(x-poscache[poscache[0]]&limit)return -1;
&KamLinearLayout.java (如果不需要支持APILevel 10及以下,可以无视这个类)
1 package com.kam.horizontalscrollviewtest.
3 import android.content.C
4 import android.util.AttributeS
5 import android.widget.LinearL
7 public class KamLinearLayout extends LinearLayout {
kamLayoutChangeListener listener = null;
public void addKamLayoutChangeListener(kamLayoutChangeListener listener){
this.listener=
public KamLinearLayout(Context context) {
super(context);
// TODO Auto-generated constructor stub
public KamLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
public void onLayout(boolean changed,
int l, int t, int r, int b){
super.onLayout(changed, l, t, r, b);
if(this.listener!=null)this.listener.onLayoutChange();
32 /*自定义监听器*/
33 interface kamLayoutChangeListener{
abstract void onLayoutChange();
MainActivity.java
1 package com.kam.hori
3 import android.support.v7.app.ActionBarA
4 import android.os.B
5 import android.view.M
6 import android.view.MenuI
8 public class MainActivity extends ActionBarActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.kamhsview);
public boolean onCreateOptionsMenu(Menu menu) {
// I this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
return super.onOptionsItemSelected(item);
kamhsview.xml
&?xml version="1.0" encoding="utf-8"?&
&com.kam.horizontalscrollviewtest.view.KamHorizontalScrollView
xmlns:android="/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/kamscrollview"
android:fadingEdge="none"
android:scrollbars="none"
&!-- 如果你不需要支持Android2.3,可以把后面的KamLinearLayout替换成普通的LinearLayout
&LinearLayout
android:id="@+id/container1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" &
&/LinearLayout & --&
&com.kam.horizontalscrollviewtest.view.KamLinearLayout
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"&
&/com.kam.horizontalscrollviewtest.view.KamLinearLayout&
&/com.kam.horizontalscrollviewtest.view.KamHorizontalScrollView&
AndroidManifest就是默认的那个,没有改。
&?xml version="1.0" encoding="utf-8"?&
&manifest xmlns:android="/apk/res/android"
package="com.kam.horizontalscrollviewtest"
android:versionCode="1"
android:versionName="1.0" &
android:minSdkVersion="8"
android:targetSdkVersion="10" /&
&application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppBaseTheme" &
android:name=".MainActivity"
android:label="@string/app_name" &
&intent-filter&
&action android:name="android.intent.action.MAIN" /&
&category android:name="android.intent.category.LAUNCHER" /&
&/intent-filter&
&/activity&
&/application&
&/manifest&

我要回帖

更多关于 horizontalscroview 的文章

 

随机推荐