android ListView加HeadView左右切换图片(类似各大新闻客户端)
2023-09-14 08:59:39 时间
我简单的介绍下实现方法:其实就是listview addHeaderView.只不过这个view是一个可以切换图片的view,至于这个view怎么做,就要根据自己的喜爱了,实现有多种方法,下面我简单介绍一下.
第一种:ViewFlipper+GestureDetector
主布局就是一个listview,这里就不介绍了,我介绍下切换图片布局
head_iamge.xml
这里我就添加一系列切换点,至于显示新闻标题,透明效果等等,大家可以自己布局,方法同理,不难实现.
接下来我们看动画布局. push_left_in.xml
push_right_in.xml
push_right_out.xml
我简单介绍下这些布局:
push_left_in:左边进入,则要进入的view初始位置在-100%p位置,终止位置在0,而push_left_out:左边出来,则此时view的位置在0,而终止位置在-100%p. 右进右出同理,至于alpha渐变,很简单,动画就说道这里,相信了解动画的同学们不用看就ok了.
下面重点是如何实现. 代码: MainActivity.java
大家一看就明白了,我们只对position==0进行手势监听,也许有人问了,其实也可以直接在MainActivity中的dispatchTouchEvent分发事件中获取点击listview的position,可是这样不准确,我点击第0项获取的有的是0,有的是1,原因目前不明,不过但可以肯定,这样是能获取listview的position的,所以就干脆自定义吧,这样不会出错.这样解决了不会滑动下面item图片跟着切换.
再有就是我们要把listview item的第一项 onclick事件禁止了,我们直接把这个点击事件搬到onSingleTapUp中,这样就不会因为手势操作而影响item的onclick事件了,这样问题基本都解决了,其实我想有简单的方法,只要把Touch事件弄懂,可惜啊...不给力啊... 效果和上面一样. 经过多次测试,目前没有发现问题,如有不妥我会给出提示.
这样viewpager滑动就不会受listview干扰了,listview上下也可以滑动. 由于自己对事件分发不是很了解,所以不过多介绍,想知道的话,自己慢慢研究吧,我这里只是提供一个解决方法,我也在学习中... 其他部分不难,这里就不讲解了. 感觉还是第二种方法好,这也是为什么那么多客户端都是这么搞,不过各有千秋,因人而异.
对第二种方法实现简单讲解: 我们的目的是:我们左右滑动ViewPager的时候ListView不影响,而当ViewPager上下滑动的时候可以随意滑动. 我们可以这样做:我们把onInterceptTouchEvent返回值更改为fase,那么意味着,如果孩子存在onInterceptTouchEvent那么会继续传递给孩子的onInterceptTouchEvent...后面我们不管(此时ListView失去touch事件),这个时候ViewPager获取Touch事件. 这个时候ViewPager就可以左右滑动(不可以上下滑动)。 如果孩子不存在onInterceptTouchEvent,ListView执行本身ontouch. 那么把onInterceptTouchEvent返回值更改为true.意思就是:我对touch事件进行拦截,不进行向下传递,直接执行自身的Ontouch事件,这个时候ViewPager就可以上下滑了(不可以左右滑动切换). 根据实情,那么我们如何动态控制这个onInterceptTouchEvent的返回值,这个时候我们可以借助:GestureDetector手势来实现.
上面这个方法可以根据手势来判断我们手的滑动方向.而:boolean b = mGestureDetector.onTouchEvent(ev);
这个值就是onScroll返回的值.这个值是代表我们手势mGestureDetector消费了没,为什么这么说呢,因为这个和我们外界的touch分开了,就算我们在这里消费了那么外面该怎么执行就怎么执行。经过测试觉得mGestureDetector.onTouchEvent(ev)这个方法就是执行手势相应方法,然后返回的是onScroll的返回值. 而当我们上下滑动的时候mGestureDetector.onTouchEvent(ev)返回true,而ViewPager需要上下滑动的时候只需要将onInterceptTouchEvent的返回值更改为true,左右滑动同理. 那么这样我们就实现了ViewPager与ListView滑动的冲突.
Android 组件化(一)项目模式管理、模式切换 在进行安装开发的时候我们经常会对项目进行不同业务逻辑处理分包,例如专门处理网络、数据库、业务逻辑代码的,如果我们不分包则所有东西写在一起,势必在开发过程中会浪费很多时间在寻找文件上,而分包的思想源于模块化,例如一些utils类,专门放到一个包下面,这样在使用的时候就能很快找到。节省开发时间,降低后期维护成本,那么组件化是什么?
Android TabLayout 加 ViewPager实现选项卡切换功能 今天讲一个很简单的功能,就是可以切换的选项卡功能,很多app都有类似这种效果,实现的方法也有很多,这里我采用TabLayout加上ViewPager来实现,这里我做了一个封装,相当于一个工具类来着,哪个地方需要用到都可以使用,使用上我的那个封装类就可以了。
?xml version="1.0" encoding="utf-8"? LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" FrameLayout android:id="@+id/fl_main" android:layout_width="match_parent" android:layout_height="wrap_content" ViewFlipper android:id="@+id/ViewFlipper01" android:layout_width="fill_parent" android:layout_height="fill_parent" /ViewFlipper LinearLayout android:id="@+id/ll_point" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom|center_horizontal" android:layout_marginBottom="10dp" android:src="@drawable/indicator" / /FrameLayout /LinearLayout
这里我就添加一系列切换点,至于显示新闻标题,透明效果等等,大家可以自己布局,方法同理,不难实现.
接下来我们看动画布局. push_left_in.xml
?xml version="1.0" encoding="utf-8"? set xmlns:android="http://schemas.android.com/apk/res/android" android:fillAfter="true" translate android:duration="500" android:fromXDelta="-100%p" android:toXDelta="0" / alpha android:duration="500" android:fromAlpha="0.1" android:toAlpha="1.0" / /set
push_left_out.xml
?xml version="1.0" encoding="utf-8"? set xmlns:android="http://schemas.android.com/apk/res/android" translate android:duration="500" android:fromXDelta="0" android:toXDelta="-100%p" / alpha android:duration="500" android:fromAlpha="1.0" android:toAlpha="0.5" / /set
push_right_in.xml
?xml version="1.0" encoding="utf-8"? set xmlns:android="http://schemas.android.com/apk/res/android" android:fillAfter="true" translate android:duration="500" android:fromXDelta="100%p" android:toXDelta="0" / alpha android:duration="500" android:fromAlpha="0.1" android:toAlpha="1.0" / /set
push_right_out.xml
?xml version="1.0" encoding="utf-8"? set xmlns:android="http://schemas.android.com/apk/res/android" translate android:duration="500" android:fromXDelta="0" android:toXDelta="100%p" / alpha android:duration="500" android:fromAlpha="1.0" android:toAlpha="0.5" / /set
我简单介绍下这些布局:
push_left_in:左边进入,则要进入的view初始位置在-100%p位置,终止位置在0,而push_left_out:左边出来,则此时view的位置在0,而终止位置在-100%p. 右进右出同理,至于alpha渐变,很简单,动画就说道这里,相信了解动画的同学们不用看就ok了.
下面重点是如何实现. 代码: MainActivity.java
import java.util.ArrayList; import java.util.Timer; import java.util.TimerTask; import android.app.Activity; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Matrix; import android.os.Bundle; import android.util.Log; import android.view.GestureDetector; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.View.OnTouchListener; import android.view.animation.AnimationUtils; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.Button; import android.widget.ImageView.ScaleType; import android.widget.LinearLayout.LayoutParams; import android.widget.ArrayAdapter; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ListView; import android.widget.TextView; import android.widget.Toast; import android.widget.ViewFlipper; public class MainActivity extends Activity implements GestureDetector.OnGestureListener { private GestureDetector detector; private ViewFlipper flipper; private int image_id[] = { R.drawable.a, R.drawable.b, R.drawable.c }; private ListView lv_main; private LayoutInflater layoutInflater; private LinearLayout ll_point; private FrameLayout frameLayout; private final String msg[] = { "one", "two", "three", "four", "five", "six", "seven" }; private int frameheight;// 图片的高度 private int window_width;// 屏幕宽度 private ArrayList ImageView imageViews;// ponit 集合 private ArrayList View views;// flipper的孩子 private Timer timer; /*** * 初始化 point void initPoint() { imageViews = new ArrayList ImageView ImageView imageView; for (int i = 0; i image_id.length; i++) { imageView = new ImageView(this); imageView.setBackgroundResource(R.drawable.indicator); LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams( new ViewGroup.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); layoutParams.leftMargin = 10; layoutParams.rightMargin = 10; ll_point.addView(imageView, layoutParams); imageViews.add(imageView); /*** * ChildView void initChildView(ViewFlipper flipper) { views = new ArrayList View LayoutParams layoutParams = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT); for (int i = 0; i image_id.length; i++) { ImageView imageView = new ImageView(this); imageView.setScaleType(ScaleType.FIT_XY); Bitmap bitmap = BitmapFactory.decodeResource(getResources(), image_id[i]); Bitmap bitmap2 = getBitmap(bitmap, window_width); frameheight = bitmap2.getHeight();// 获取要显示的高度 imageView.setImageResource(image_id[i]); flipper.addView(imageView, layoutParams); views.add(imageView); initPoint(); /*** * 初始化 HeadImage void initHeadImage() { layoutInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); View headview = layoutInflater.inflate(R.layout.head_image, null); flipper = (ViewFlipper) headview.findViewById(R.id.ViewFlipper01); ll_point = (LinearLayout) headview.findViewById(R.id.ll_point); frameLayout = (FrameLayout) headview.findViewById(R.id.fl_main); initChildView(flipper); LayoutParams layoutParams = (LayoutParams) frameLayout .getLayoutParams(); layoutParams.height = frameheight; frameLayout.setLayoutParams(layoutParams); draw_Point(0);// 默认首次进入 lv_main.addHeaderView(headview);// 要卸载setAdapter前面 lv_main.setAdapter(new ArrayAdapter String (this, android.R.layout.simple_list_item_1, msg)); /*** * init view void initView() { setTitle("jjhappyforever..."); setContentView(R.layout.main); lv_main = (ListView) findViewById(R.id.lv_main); lv_main.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView ? parent, View view, int position, long id) { if (position != 0) Toast.makeText(MainActivity.this, msg[position - 1], 1) .show(); else { int index = getPageIndex(flipper.getCurrentView()); Toast.makeText(MainActivity.this, "图" + index, 1).show(); initHeadImage(); /*** * 更新选中点 * @param index private void draw_Point(int index) { for (int i = 0; i imageViews.size(); i++) { imageViews.get(i).setImageResource(R.drawable.indicator); imageViews.get(index).setImageResource(R.drawable.indicator_focused); @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // 获取屏幕的宽度 window_width = (int) getResources().getDimension(R.dimen.window_width); detector = new GestureDetector(this); initView(); timer = new Timer(true); timer.schedule(new TimerTask() { @Override public void run() { runOnUiThread(new Runnable() { @Override public void run() { int pageIndex = getPageIndex(flipper.getCurrentView()); if (pageIndex == flipper.getChildCount() - 1) pageIndex = 0; else pageIndex++; flipper.setInAnimation(AnimationUtils.loadAnimation( MainActivity.this, R.anim.push_right_in)); flipper.setOutAnimation(AnimationUtils.loadAnimation( MainActivity.this, R.anim.push_left_out)); flipper.showNext(); draw_Point(pageIndex); }, 5000, 5000); /*** * 对图片处理 * @author zhangjia Bitmap getBitmap(Bitmap bitmap, int width) { int w = bitmap.getWidth(); int h = bitmap.getHeight(); Matrix matrix = new Matrix(); float scale = (float) width / w; // 保证图片不变形. matrix.postScale(scale, scale); // w,h是原图的属性. return Bitmap.createBitmap(bitmap, 0, 0, w, h, matrix, true); @Override public boolean dispatchTouchEvent(MotionEvent ev) { this.detector.onTouchEvent(ev); return super.dispatchTouchEvent(ev); @Override public boolean onDown(MotionEvent e) { return true; /*** * 返回当前第几屏 int getPageIndex(View view) { for (int i = 0; i views.size(); i++) { if (view == views.get(i)) return i; return 0; * 监听滑动 @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { int pageIndex = getPageIndex(flipper.getCurrentView()); // 左划 if (e1.getX() - e2.getX() 120) { this.flipper.setInAnimation(AnimationUtils.loadAnimation(this, R.anim.push_right_in)); this.flipper.setOutAnimation(AnimationUtils.loadAnimation(this, R.anim.push_left_out)); this.flipper.showNext(); if (pageIndex == flipper.getChildCount() - 1) draw_Point(0); else draw_Point(++pageIndex); return true; // 右划 } else if (e1.getX() - e2.getX() -120) { this.flipper.setInAnimation(AnimationUtils.loadAnimation(this, R.anim.push_left_in)); this.flipper.setOutAnimation(AnimationUtils.loadAnimation(this, R.anim.push_right_out)); this.flipper.showPrevious(); if (pageIndex == 0) draw_Point(flipper.getChildCount() - 1); else draw_Point(--pageIndex); return true; return true; @Override public void onLongPress(MotionEvent e) { @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { return false; @Override public void onShowPress(MotionEvent e) { @Override public boolean onSingleTapUp(MotionEvent e) { return false; }
@Override public boolean onTouchEvent(MotionEvent ev) { Log.e("jj", "onTouchEvent..."); int x = (int) ev.getX(); int y = (int) ev.getY(); int position = pointToPosition(x, y); // 只有headview才进行手势操作. if (position == 0) { // 注入手势 gestureDetector.onTouchEvent(ev); return super.onTouchEvent(ev); }
大家一看就明白了,我们只对position==0进行手势监听,也许有人问了,其实也可以直接在MainActivity中的dispatchTouchEvent分发事件中获取点击listview的position,可是这样不准确,我点击第0项获取的有的是0,有的是1,原因目前不明,不过但可以肯定,这样是能获取listview的position的,所以就干脆自定义吧,这样不会出错.这样解决了不会滑动下面item图片跟着切换.
再有就是我们要把listview item的第一项 onclick事件禁止了,我们直接把这个点击事件搬到onSingleTapUp中,这样就不会因为手势操作而影响item的onclick事件了,这样问题基本都解决了,其实我想有简单的方法,只要把Touch事件弄懂,可惜啊...不给力啊... 效果和上面一样. 经过多次测试,目前没有发现问题,如有不妥我会给出提示.
第二种方法:ViewPager.
viewpager效果相比大家都熟知,因此我就省略显示的那部分,方法和上面一样,只是显示用的是viewpager而已. 但是这里面存在一个严重的问题:ViewPager和listview共存的问题,二者都有自身的滑动事件,必然要产生冲突。viewpager操作起来相当的不灵敏. 这里我重点说一下解决办法:我们需要自定义Listview,对其拦截事件进行处理.另外我们要用手势,判断上下左右滑动.MyListView.java
import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.view.GestureDetector; import android.view.GestureDetector.SimpleOnGestureListener; import android.view.MotionEvent; import android.view.View; import android.widget.ListView; public class MyListView extends ListView { private GestureDetector mGestureDetector; View.OnTouchListener mGestureListener; public MyListView(Context context) { super(context); public MyListView(Context context, AttributeSet attrs) { super(context, attrs); mGestureDetector = new GestureDetector(new YScrollDetector()); setFadingEdgeLength(0); public MyListView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); @Override public boolean onInterceptTouchEvent(MotionEvent ev) { super.onInterceptTouchEvent(ev); return mGestureDetector.onTouchEvent(ev); class YScrollDetector extends SimpleOnGestureListener { @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { if (Math.abs(distanceY) = Math.abs(distanceX)) { Log.e("jj", "上下...."); return true; Log.e("jj", "左右...."); return false; }
这样viewpager滑动就不会受listview干扰了,listview上下也可以滑动. 由于自己对事件分发不是很了解,所以不过多介绍,想知道的话,自己慢慢研究吧,我这里只是提供一个解决方法,我也在学习中... 其他部分不难,这里就不讲解了. 感觉还是第二种方法好,这也是为什么那么多客户端都是这么搞,不过各有千秋,因人而异.
对第二种方法实现简单讲解: 我们的目的是:我们左右滑动ViewPager的时候ListView不影响,而当ViewPager上下滑动的时候可以随意滑动. 我们可以这样做:我们把onInterceptTouchEvent返回值更改为fase,那么意味着,如果孩子存在onInterceptTouchEvent那么会继续传递给孩子的onInterceptTouchEvent...后面我们不管(此时ListView失去touch事件),这个时候ViewPager获取Touch事件. 这个时候ViewPager就可以左右滑动(不可以上下滑动)。 如果孩子不存在onInterceptTouchEvent,ListView执行本身ontouch. 那么把onInterceptTouchEvent返回值更改为true.意思就是:我对touch事件进行拦截,不进行向下传递,直接执行自身的Ontouch事件,这个时候ViewPager就可以上下滑了(不可以左右滑动切换). 根据实情,那么我们如何动态控制这个onInterceptTouchEvent的返回值,这个时候我们可以借助:GestureDetector手势来实现.
/*** * @author zhangjia class YScrollDetector extends SimpleOnGestureListener { @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { if (Math.abs(distanceY) = Math.abs(distanceX)) { Log.e("jj", "上下...."); return true; Log.e("jj", "左右...."); return false; }
上面这个方法可以根据手势来判断我们手的滑动方向.而:boolean b = mGestureDetector.onTouchEvent(ev);
这个值就是onScroll返回的值.这个值是代表我们手势mGestureDetector消费了没,为什么这么说呢,因为这个和我们外界的touch分开了,就算我们在这里消费了那么外面该怎么执行就怎么执行。经过测试觉得mGestureDetector.onTouchEvent(ev)这个方法就是执行手势相应方法,然后返回的是onScroll的返回值. 而当我们上下滑动的时候mGestureDetector.onTouchEvent(ev)返回true,而ViewPager需要上下滑动的时候只需要将onInterceptTouchEvent的返回值更改为true,左右滑动同理. 那么这样我们就实现了ViewPager与ListView滑动的冲突.
好了,就写到这里了,下面给一个Demo,大家可以拿去看看!
http://download.csdn.net/detail/gulaer/4965682
Android 组件化(一)项目模式管理、模式切换 在进行安装开发的时候我们经常会对项目进行不同业务逻辑处理分包,例如专门处理网络、数据库、业务逻辑代码的,如果我们不分包则所有东西写在一起,势必在开发过程中会浪费很多时间在寻找文件上,而分包的思想源于模块化,例如一些utils类,专门放到一个包下面,这样在使用的时候就能很快找到。节省开发时间,降低后期维护成本,那么组件化是什么?
Android TabLayout 加 ViewPager实现选项卡切换功能 今天讲一个很简单的功能,就是可以切换的选项卡功能,很多app都有类似这种效果,实现的方法也有很多,这里我采用TabLayout加上ViewPager来实现,这里我做了一个封装,相当于一个工具类来着,哪个地方需要用到都可以使用,使用上我的那个封装类就可以了。
相关文章
- Android 再次探究Fragment在各种情况下的onResume与onPause
- android 浏览器 开发,Android 浏览器的开发实例分享
- Android RSA 加密
- android 常用加密,分享一下Android各种类型的加密
- android签名命令行,Android系统签名位置及命令
- android activitymanager 系统api_Android view
- Android RecyclerView使用简述
- android跳转到相册需要权限,Android打开相册获取图片路径[通俗易懂]
- 【Android 逆向】类加载器 ClassLoader ( 启动类加载器 | 扩展类加载器 | 应用类加载器 | 类加载的双亲委托机制 )
- 【Android Gradle 插件】Module 目录下 build.gradle 配置文件 ( android 闭包块配置 | AppExtension 扩展类型参考文档 )
- 【ijkplayer】编译 Android 版本的 ijkplayer ⑤ ( 执行 init-android-libyuv.sh | 执行 init-android-soundtouch.sh )
- 【Android Gradle 插件】Gradle 依赖管理 ④ ( Android Gradle 插件中注册的依赖分组 | implementation | api | compileOnly )
- android项目 微博客户端 源码详解手机开发
- android的activity栈管理详解手机开发
- 再谈Android客户端进程保活详解手机开发
- 再谈Android动态链接库详解手机开发
- Android Studio 导入项目 出现安装Error:Cause: failed to find target with hash string ‘android-23’ 等错误详解手机开发
- win10 编译 Android ffmpeg详解手机开发
- 2013年上半年Android平台病毒同比增长7.96倍
- Android系统基于Linux内核,实现移动设备突破极限。(android linux内核)
- Android的文本和输入之创建输入法教程
- Android开发笔记之:ListView刷新顺序的问题详解
- Android???虹?搴????ュ共?规??荤?