Android仿京東首頁畫軸效果
記得之前京東首頁有一個(gè)效果,有一個(gè)畫軸,然后可以滾動(dòng)畫軸,去打開畫(不知道怎么去形容這個(gè)效果,就叫做畫軸效果吧- -!),然后去做相關(guān)操作,剛開始看到這個(gè)效果,想法是動(dòng)態(tài)的去改變一個(gè)ImageView的高度,基本效果也就出來了,不過滾動(dòng)部分的內(nèi)容,當(dāng)時(shí)接觸的也不是很多,只是看過一些大牛的博客,略微了解了一點(diǎn),當(dāng)時(shí)也忙著寫項(xiàng)目,也就沒去多想,前些天忽然想到這個(gè)效果,就想著實(shí)現(xiàn)一下,不過京東新版本好像去掉這個(gè)東西了,只能憑著自己的記憶來大概搞一下,也是對(duì)滑動(dòng)這部分內(nèi)容的一個(gè)小練習(xí)吧.
先看一下效果圖:
一、需求分析
看到效果之后,先來分析一下:
首先是需要一個(gè)可以滑動(dòng)的畫軸,并且這個(gè)畫軸需要一定的滑動(dòng)空間,有滑動(dòng)的效果,這個(gè)用Scroller幫助完成就可以了.
然后看一下畫軸點(diǎn)擊移動(dòng)時(shí)候的背景圖,是跟隨畫軸移動(dòng),動(dòng)態(tài)改變高度的.這個(gè)用一個(gè)ImageView來搞定,設(shè)置ImageView的scaleType就可以了,不過這個(gè)地方有一些小問題,下面會(huì)說.
二、具體實(shí)現(xiàn)
簡(jiǎn)單分析完,來實(shí)現(xiàn)一下,先來做一下畫軸.創(chuàng)建一個(gè)ScrollPaintView繼承自RelativeLayout,因?yàn)樾枰欢ǖ幕瑒?dòng)空間,所以需要是一個(gè)ViewGroup.
ScrollPaintView的一些基本屬性:
public class ScrollPaintView extends RelativeLayout { /** * TAG */ private static final String TAG = "ScrollPaintView"; /** * 默認(rèn)滾軸高度 */ private final int DEFAULT_PAINT_SCROLL_HEIGHT = 25; /** * 默認(rèn)滾動(dòng)的速度 */ private final int DEFAULT_SCROLL_SPEED = 1000; /** * 默認(rèn)分割點(diǎn)高度 */ private final int DEFAULT_PARTITION_NODE = 150; /** * 默認(rèn)畫軸文字大小 */ private final int DEFAULT_PAINT_SCROLL_TXT_SIZE = 16; /** * Scroller */ private Scroller mScroller; /** * 滾軸Iv */ private ImageView mPaintScrollImageView; /** * 滾軸Tv */ private TextView mPaintScrollTextView; /** * 圖畫Iv */ private ImageView mPaintView; /** * 畫軸圖 */ private Bitmap mPaintScrollBp; /** * 畫軸高度 */ private int mPaintIvHeight; /** * 畫軸文字 */ private String mPaintScrollTxt; /** * 畫軸文字大小 */ private float mPaintScrollTxtSize; /** * 畫軸文字顏色 */ private int mPaintScrollTxtColor; /** * 圖畫開始時(shí)的高度 */ private int mPaintStartHeight; /** * 上一次獲取的Y */ private int mLastY; /** * 滾動(dòng)速度 */ private int mScrollSpeed; /** * 分隔節(jié)點(diǎn) */ private int partitionNode; /** * 是否是向上滾動(dòng) */ private boolean isScrllerTop = false; /** * 是否正在點(diǎn)擊 */ private boolean isClick = false; /** * 布局參數(shù) */ private LayoutParams lpp; /** * 屏幕高度 */ private int screenHeight; /** * 屏幕寬度 */ private int screenWidth; /** * 回調(diào)監(jiān)聽 */ private ScrollPaintCompleteListener listener; /** * 上一次滾動(dòng)的Y值 */ private int lastScrollY; /** * 構(gòu)造方法 */ public ScrollPaintView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); // 獲取屬性 TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.ScrollPaintView); mPaintIvHeight = (int) ta.getDimension(R.styleable.ScrollPaintView_paintScrollHeight, TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP, DEFAULT_PAINT_SCROLL_HEIGHT, getResources().getDisplayMetrics())); mScrollSpeed = ta.getInteger(R.styleable.ScrollPaintView_scrollSpeed, DEFAULT_SCROLL_SPEED); partitionNode = ta.getInteger(R.styleable.ScrollPaintView_scrollPartitionNode, DEFAULT_PARTITION_NODE); mPaintScrollBp = drawableToBitamp(ta.getDrawable(R.styleable.ScrollPaintView_paintScrollSrc)); mPaintScrollTxt = ta.getString(R.styleable.ScrollPaintView_paintScrollTxt); mPaintScrollTxtColor = ta.getColor(R.styleable.ScrollPaintView_paintScrollTxtColor, Color.BLACK); mPaintScrollTxtSize = px2sp(ta.getDimensionPixelSize(R.styleable.ScrollPaintView_paintScrollTxtSize, DEFAULT_PAINT_SCROLL_TXT_SIZE)); ta.recycle(); } }
看一下創(chuàng)建畫軸:
/** * 創(chuàng)建滾軸 */ private void makePaintScroll() { // 如果已經(jīng)存在,則不再創(chuàng)建 if (null != mPaintScrollImageView || null != mPaintScrollTextView) { return; } // 創(chuàng)建滾軸 mPaintScrollImageView = new ImageView(getContext()); LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); lp.height = mPaintIvHeight; mPaintScrollImageView.setLayoutParams(lp); mPaintScrollImageView.setScaleType(ImageView.ScaleType.FIT_XY); mPaintScrollImageView.setImageBitmap(null == mPaintScrollBp ? makeDefaultScroll() : mPaintScrollBp); addView(mPaintScrollImageView); // 創(chuàng)建文字 mPaintScrollTextView = new TextView(getContext()); LayoutParams lpt = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); lpt.height = mPaintIvHeight; mPaintScrollTextView.setLayoutParams(lpt); mPaintScrollTextView.setText(null == mPaintScrollTxt ? "" : mPaintScrollTxt); mPaintScrollTextView.setTextSize(mPaintScrollTxtSize); mPaintScrollTextView.setTextColor(mPaintScrollTxtColor); mPaintScrollTextView.setGravity(Gravity.CENTER); addView(mPaintScrollTextView); } /** * 設(shè)置默認(rèn)的滾軸 * * @return */ private Bitmap makeDefaultScroll() { Bitmap defaultBp = Bitmap.createBitmap(screenWidth, mPaintIvHeight, Bitmap.Config.ARGB_8888); //填充顏色 defaultBp.eraseColor(Color.parseColor("#FF0000")); return defaultBp; }
創(chuàng)建了一個(gè)畫軸ImageView和一個(gè)文字TextView作為初始的畫軸,如果沒有傳入畫軸的圖片,則默認(rèn)去創(chuàng)建一個(gè)畫軸.不難理解,接著去配合Scroller,讓畫軸滾動(dòng)起來.
簡(jiǎn)單滾動(dòng):
/** * 處理View */ private void handleView() { // 初始化Scroller mScroller = new Scroller(getContext()); // 畫軸點(diǎn)擊效果 mPaintScrollImageView.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View view, MotionEvent event) { int x = (int) event.getRawX(); int y = (int) event.getRawY(); int action = event.getAction(); switch (action) { case MotionEvent.ACTION_DOWN: isClick = true; mLastY = y; if (!mScroller.isFinished()) { // 如果上次的調(diào)用沒有執(zhí)行完就取消。 mScroller.abortAnimation(); } return true; case MotionEvent.ACTION_MOVE: // 移動(dòng)的距離 int dy = y - mLastY; mLastY = y; // 滑動(dòng) scrollBy(0, -dy); return true; case MotionEvent.ACTION_UP: mScroller.startScroll(getScrollX(), getScrollY(), -getScrollX(), -getScrollY(), 1000); invalidate(); return true; } return false; } }); } /** * 滑動(dòng)處理 */ @Override public void computeScroll() { if (mScroller.computeScrollOffset()) { // 計(jì)算新位置,并判斷上一個(gè)滾動(dòng)是否完成。 scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); invalidate(); } }
這樣滑動(dòng)處理就做完了,在布局中引用一下,看一下效果
activity_main:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#eeeeee" tools:context="com.example.junweiliu.scrollpaintdemo.MainActivity"> <!--畫軸控件--> <com.example.junweiliu.scrollpaintdemo.widget.ScrollPaintView android:id="@+id/spv_paint" android:layout_width="match_parent" android:layout_height="match_parent" app:paintScrollHeight="25dp" app:paintScrollSrc="@mipmap/paint_scroll_img" app:paintScrollTxt="拉我看看" app:paintScrollTxtColor="#FF000000" app:paintScrollTxtSize="16sp" > </com.example.junweiliu.scrollpaintdemo.widget.ScrollPaintView> </RelativeLayout>
效果圖:
滾動(dòng)條基本能用了,接著來設(shè)置一個(gè)ImageView來配合使用下,先獲取到一個(gè)ImageView,然后拖動(dòng)畫軸時(shí),來動(dòng)態(tài)改變ImageView的高度,在做這部分內(nèi)容前,先來考慮下,因?yàn)樾枨笮枰氖菆D畫整體不會(huì)變形,是一點(diǎn)一點(diǎn)拉開的感覺,就像是打開一幅畫一樣,那么用哪種scaleType能滿足呢.試了好多種,來分別看一下:
相關(guān)代碼:
提供一個(gè)設(shè)置ImageView的方法
在MotionEvent.ACTION_MOVE:中動(dòng)態(tài)改變ImageView的高度
滑動(dòng)時(shí)動(dòng)態(tài)改變ImageView的高度
/** * 設(shè)置paintView * * @param paintView */ public void setPaintView(ImageView paintView) { if (null == paintView) { Log.e(TAG, "設(shè)置的View為空"); return; } mPaintView = paintView; }
MotionEvent.ACTION_MOVE:
// 滑動(dòng)處理 case MotionEvent.ACTION_MOVE: ... // 動(dòng)態(tài)改變高度 if (Math.abs(getScrollY()) > 0) { lpp.height = mPaintStartHeight + Math.abs(getScrollY()); mPaintView.setLayoutParams(lpp); }
滑動(dòng)處理:
/** * 滑動(dòng)處理 */ @Override public void computeScroll() { if (mScroller.computeScrollOffset()) { // 計(jì)算新位置,并判斷上一個(gè)滾動(dòng)是否完成。 // 請(qǐng)求處理點(diǎn)擊事件,防止父控件滑動(dòng) requestDisallowInterceptTouchEvent(true); scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); // 重新設(shè)置顯示的控件高度 if (0 < Math.abs(mScroller.getCurrY())) { if (!isScrllerTop) { lpp.height = mPaintStartHeight + Math.abs(mScroller.getCurrY()) + mPaintIvHeight / 2; } else { lpp.height = mPaintStartHeight + Math.abs(mScroller.getCurrY()) - mPaintIvHeight / 2; } } else { lpp.height = mPaintStartHeight; } mPaintView.setLayoutParams(lpp); invalidate(); } }
設(shè)置不同scaleType效果,簡(jiǎn)單試幾個(gè)效果:
fitXY:
centerCrop:
matrix:
觀察一下,好像那個(gè)效果都不是很好,不過matrix拉開的效果和預(yù)期需要的是一樣的,不過用matrix之后,就沒有辦法設(shè)置其他scaleType了,沒辦法把圖片進(jìn)行縮放了,這腫么辦呢,其實(shí)很簡(jiǎn)單,只需要把顯示的圖片提前進(jìn)行一下縮放就可以了.
處理圖片相關(guān):
/** * 設(shè)置paintView * * @param paintView */ public void setPaintView(ImageView paintView) { if (null == paintView) { Log.e(TAG, "設(shè)置的View為空"); return; } // 處理圖片,對(duì)圖片按照屏幕寬高比進(jìn)行縮放 Bitmap bp = drawableToBitamp(paintView.getDrawable()); paintView.setImageBitmap(scaleBitmal(bp)); // 設(shè)置縮放形式 paintView.setScaleType(ImageView.ScaleType.MATRIX); mPaintView = paintView; } /** * drawable轉(zhuǎn)bitmap * * @param drawable * @return */ private Bitmap drawableToBitamp(Drawable drawable) { if (null == drawable) { return null; } if (drawable instanceof BitmapDrawable) { BitmapDrawable bd = (BitmapDrawable) drawable; return bd.getBitmap(); } int w = drawable.getIntrinsicWidth(); int h = drawable.getIntrinsicHeight(); Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); drawable.setBounds(0, 0, w, h); drawable.draw(canvas); return bitmap; } /** * 按照屏幕寬高縮放圖片 * * @param bp * @return */ private Bitmap scaleBitmal(Bitmap bp) { // 寬度比例 float scaleW = (float) screenWidth / (float) bp.getWidth(); // 高度比例 float scaleH = (float) screenHeight / (float) bp.getHeight(); // 矩陣,用于縮放圖片 Matrix matrix = new Matrix(); matrix.postScale(scaleW, scaleH); // 縮放后的圖片 Bitmap scaleBp = Bitmap.createBitmap(bp, 0, 0, bp.getWidth(), bp.getHeight(), matrix, true); return scaleBp; }
看一下效果:
效果還不錯(cuò),接下來就是做一下細(xì)節(jié)上的處理,設(shè)置一個(gè)臨界點(diǎn),讓畫軸向上或者向下滾動(dòng),設(shè)置邊界點(diǎn),讓畫軸不越界等等.還有一般都是在ScrollView中使用到這個(gè)效果,所以要去處理一下事件沖突,當(dāng)然還有去重寫一下onMeasure方法,不然會(huì)出現(xiàn)不顯示的情況.(相信大家也遇到過ScrollView里邊嵌套ListView導(dǎo)致ListView顯示不全)這里就不再詳細(xì)介紹了.直接貼下代碼.
三、完整代碼
MainActivity:
package com.example.junweiliu.scrollpaintdemo; import android.content.Intent; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast; import com.example.junweiliu.scrollpaintdemo.widget.ScrollPaintView; public class MainActivity extends AppCompatActivity { private static final String TAG = "MainActivity"; /** * 需要顯示的IV */ private ImageView mPaintIv; /** * 畫軸 */ private ScrollPaintView mScrollPaintView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); } /** * 初始化控件 */ private void initView() { mPaintIv = (ImageView) findViewById(R.id.iv_paint); mScrollPaintView = (ScrollPaintView) findViewById(R.id.spv_paint); mScrollPaintView.setPaintView(mPaintIv); mPaintIv.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Toast.makeText(MainActivity.this, "功夫!", Toast.LENGTH_SHORT).show(); } }); mScrollPaintView.setScrollPaintCompleteListener(new ScrollPaintView.ScrollPaintCompleteListener() { @Override public void onScrollTouch(TextView tv) { mPaintIv.setVisibility(View.VISIBLE); } @Override public void onScrollTop(TextView tv) { // Log.e(TAG, "收縮了"); tv.setText("拉我看看"); if (View.VISIBLE == mPaintIv.getVisibility()) { mPaintIv.setVisibility(View.GONE); } } @Override public void onScrollBottom(TextView tv) { // Log.e(TAG, "展開了"); tv.setText("到底了"); Intent intent = new Intent(MainActivity.this, DetailActivity.class); startActivity(intent); // 延遲800毫秒重置位置 new Handler(new Handler.Callback() { @Override public boolean handleMessage(Message message) { mScrollPaintView.replaceScroll(); return false; } }).sendEmptyMessageDelayed(0, 600); } @Override public void onScrollMove(TextView tv) { // Log.e(TAG, "移動(dòng)了"); tv.setText("請(qǐng)上下拖動(dòng)"); } }); } }
ScrollPaintView:
package com.example.junweiliu.scrollpaintdemo.widget; import android.app.Activity; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Matrix; import android.graphics.Rect; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.Log; import android.util.TypedValue; import android.view.Gravity; import android.view.MotionEvent; import android.view.View; import android.widget.ImageView; import android.widget.RelativeLayout; import android.widget.Scroller; import android.widget.TextView; import com.example.junweiliu.scrollpaintdemo.R; /** * Created by junweiliu on 16/12/10. */ public class ScrollPaintView extends RelativeLayout { /** * TAG */ private static final String TAG = "ScrollPaintView"; /** * 默認(rèn)滾軸高度 */ private final int DEFAULT_PAINT_SCROLL_HEIGHT = 25; /** * 默認(rèn)滾動(dòng)的速度 */ private final int DEFAULT_SCROLL_SPEED = 1000; /** * 默認(rèn)分割點(diǎn)高度 */ private final int DEFAULT_PARTITION_NODE = 150; /** * 默認(rèn)畫軸文字大小 */ private final int DEFAULT_PAINT_SCROLL_TXT_SIZE = 16; /** * Scroller */ private Scroller mScroller; /** * 滾軸Iv */ private ImageView mPaintScrollImageView; /** * 滾軸Tv */ private TextView mPaintScrollTextView; /** * 圖畫Iv */ private ImageView mPaintView; /** * 畫軸圖 */ private Bitmap mPaintScrollBp; /** * 畫軸高度 */ private int mPaintIvHeight; /** * 畫軸文字 */ private String mPaintScrollTxt; /** * 畫軸文字大小 */ private float mPaintScrollTxtSize; /** * 畫軸文字顏色 */ private int mPaintScrollTxtColor; /** * 圖畫開始時(shí)的高度 */ private int mPaintStartHeight; /** * 上一次獲取的Y */ private int mLastY; /** * 滾動(dòng)速度 */ private int mScrollSpeed; /** * 分隔節(jié)點(diǎn) */ private int partitionNode; /** * 是否是向上滾動(dòng) */ private boolean isScrllerTop = false; /** * 是否正在點(diǎn)擊 */ private boolean isClick = false; /** * 布局參數(shù) */ private LayoutParams lpp; /** * 屏幕高度 */ private int screenHeight; /** * 屏幕寬度 */ private int screenWidth; /** * 回調(diào)監(jiān)聽 */ private ScrollPaintCompleteListener listener; /** * 上一次滾動(dòng)的Y值 */ private int lastScrollY; /** * 回調(diào)接口 */ public interface ScrollPaintCompleteListener { /** * 點(diǎn)擊時(shí)的回調(diào) */ public void onScrollTouch(TextView tv); /** * 收縮時(shí)的回調(diào) */ public void onScrollTop(TextView tv); /** * 展開時(shí)的回調(diào) */ public void onScrollBottom(TextView tv); /** * 滾動(dòng)中的回調(diào) */ public void onScrollMove(TextView tv); } public ScrollPaintView(Context context) { this(context, null); } public ScrollPaintView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public ScrollPaintView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); // 獲取屬性 TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.ScrollPaintView); mPaintIvHeight = (int) ta.getDimension(R.styleable.ScrollPaintView_paintScrollHeight, TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP, DEFAULT_PAINT_SCROLL_HEIGHT, getResources().getDisplayMetrics())); mScrollSpeed = ta.getInteger(R.styleable.ScrollPaintView_scrollSpeed, DEFAULT_SCROLL_SPEED); partitionNode = ta.getInteger(R.styleable.ScrollPaintView_scrollPartitionNode, DEFAULT_PARTITION_NODE); mPaintScrollBp = drawableToBitamp(ta.getDrawable(R.styleable.ScrollPaintView_paintScrollSrc)); mPaintScrollTxt = ta.getString(R.styleable.ScrollPaintView_paintScrollTxt); mPaintScrollTxtColor = ta.getColor(R.styleable.ScrollPaintView_paintScrollTxtColor, Color.BLACK); mPaintScrollTxtSize = px2sp(ta.getDimensionPixelSize(R.styleable.ScrollPaintView_paintScrollTxtSize, DEFAULT_PAINT_SCROLL_TXT_SIZE)); ta.recycle(); init(); makePaintScroll(); handleView(); } /** * 設(shè)置paintView * * @param paintView */ public void setPaintView(ImageView paintView) { if (null == paintView) { Log.e(TAG, "設(shè)置的View為空"); return; } // 處理圖片,對(duì)圖片按照屏幕寬高比進(jìn)行縮放 Bitmap bp = drawableToBitamp(paintView.getDrawable()); paintView.setImageBitmap(scaleBitmal(bp)); // 設(shè)置縮放形式 paintView.setScaleType(ImageView.ScaleType.MATRIX); mPaintView = paintView; } /** * 設(shè)置回調(diào) */ public void setScrollPaintCompleteListener(ScrollPaintCompleteListener listener) { if (null != listener) { this.listener = listener; } } /** * 初始化 */ private void init() { mScroller = new Scroller(getContext()); lpp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); // 獲取屏幕信息 DisplayMetrics displayMetrics = new DisplayMetrics(); ((Activity) getContext()).getWindowManager().getDefaultDisplay() .getMetrics(displayMetrics); // 屏幕高度 screenHeight = displayMetrics.heightPixels; // 屏幕寬度 screenWidth = displayMetrics.widthPixels; } /** * 創(chuàng)建滾軸 */ private void makePaintScroll() { // 如果已經(jīng)存在,則不再創(chuàng)建 if (null != mPaintScrollImageView || null != mPaintScrollTextView) { return; } // 創(chuàng)建滾軸 mPaintScrollImageView = new ImageView(getContext()); LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); lp.height = mPaintIvHeight; mPaintScrollImageView.setLayoutParams(lp); mPaintScrollImageView.setScaleType(ImageView.ScaleType.FIT_XY); mPaintScrollImageView.setImageBitmap(null == mPaintScrollBp ? makeDefaultScroll() : mPaintScrollBp); addView(mPaintScrollImageView); // 創(chuàng)建文字 mPaintScrollTextView = new TextView(getContext()); LayoutParams lpt = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); lpt.height = mPaintIvHeight; mPaintScrollTextView.setLayoutParams(lpt); mPaintScrollTextView.setText(null == mPaintScrollTxt ? "" : mPaintScrollTxt); mPaintScrollTextView.setTextSize(mPaintScrollTxtSize); mPaintScrollTextView.setTextColor(mPaintScrollTxtColor); mPaintScrollTextView.setGravity(Gravity.CENTER); addView(mPaintScrollTextView); } /** * 測(cè)量方法 * * @param widthMeasureSpec * @param heightMeasureSpec */ @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); if (null != mPaintView && getTop() + mPaintIvHeight != mPaintView.getHeight()) { // 重新設(shè)置圖畫高度 mPaintStartHeight = getTop() + mPaintIvHeight / 2; lpp.height = mPaintStartHeight; mPaintView.setLayoutParams(lpp); } // 測(cè)量狀態(tài)欄高度 Rect frame = new Rect(); ((Activity) getContext()).getWindow().getDecorView().getWindowVisibleDisplayFrame(frame); int statusBarHeight = frame.top; // 高度為屏幕高度減去狀態(tài)欄高度和top的高度 setMeasuredDimension(screenWidth, screenHeight - getTop() - statusBarHeight); } /** * 處理View */ private void handleView() { mPaintScrollImageView.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View view, MotionEvent event) { if (null == mPaintView) { Log.e(TAG, "設(shè)置的View為空"); return true; } // 獲取點(diǎn)擊的XY坐標(biāo) int x = (int) event.getRawX(); int y = (int) event.getRawY(); int action = event.getAction(); switch (action) { case MotionEvent.ACTION_DOWN: { // 請(qǐng)求處理點(diǎn)擊事件 requestDisallowInterceptTouchEvent(true); isClick = true; mLastY = y; if (!mScroller.isFinished()) { // 如果上次的調(diào)用沒有執(zhí)行完就取消。 mScroller.abortAnimation(); } if (null != listener) { listener.onScrollTouch(mPaintScrollTextView); } return true; } case MotionEvent.ACTION_MOVE: { // 移動(dòng)的距離 int dy = y - mLastY; mLastY = y; // 滑動(dòng) scrollBy(0, -dy); // 如果是向上滑動(dòng)并且是在初始位置,則不去做處理 if (getScrollY() >= 0 && dy <= 0) { lpp.height = mPaintStartHeight; mPaintView.setLayoutParams(lpp); scrollTo(0, 0); return true; } // 如果是向下滑動(dòng)并且超過屏幕高度,則不去處理 if (Math.abs(getScrollY()) >= getHeight() - mPaintIvHeight && dy >= 0) { lpp.height = mPaintStartHeight + getHeight() - mPaintIvHeight; mPaintView.setLayoutParams(lpp); scrollTo(0, -(getHeight() - mPaintIvHeight)); return true; } // 滾動(dòng)回調(diào) if (null != listener) { listener.onScrollMove(mPaintScrollTextView); } // 重新設(shè)置顯示的控件高度 if (Math.abs(getScrollY()) > 0) { lpp.height = mPaintStartHeight + Math.abs(getScrollY()); mPaintView.setLayoutParams(lpp); } return true; } case MotionEvent.ACTION_UP: // 恢復(fù)事件處理 requestDisallowInterceptTouchEvent(false); isClick = false; // 沒有發(fā)生移動(dòng) if (getScrollY() >= 0) { if (null != listener) { listener.onScrollTop(mPaintScrollTextView); } return true; } if (-getScrollY() < partitionNode) { // 如果小于臨界值,則返回起始坐標(biāo) // XY都從滑動(dòng)的距離回去,最后一個(gè)參數(shù)是多少毫秒內(nèi)執(zhí)行完這個(gè)動(dòng)作。 isScrllerTop = true; mScroller.startScroll(getScrollX(), getScrollY(), -getScrollX(), -getScrollY(), mScrollSpeed); } else { // 如果大于臨界值,則展開 isScrllerTop = false; mScroller.startScroll(getScrollX(), getScrollY(), -getScrollX(), -(getHeight() - (-getScrollY()) - mPaintIvHeight), mScrollSpeed); } invalidate(); return true; } return false; } }); } /** * 滑動(dòng)處理 */ @Override public void computeScroll() { if (mScroller.computeScrollOffset()) { // 計(jì)算新位置,并判斷上一個(gè)滾動(dòng)是否完成。 // 請(qǐng)求處理點(diǎn)擊事件,防止父控件滑動(dòng) requestDisallowInterceptTouchEvent(true); scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); // 重新設(shè)置顯示的控件高度 if (0 < Math.abs(mScroller.getCurrY())) { if (!isScrllerTop) { lpp.height = mPaintStartHeight + Math.abs(mScroller.getCurrY()) + mPaintIvHeight / 2; } else { lpp.height = mPaintStartHeight + Math.abs(mScroller.getCurrY()) - mPaintIvHeight / 2; } } else { lpp.height = mPaintStartHeight; } mPaintView.setLayoutParams(lpp); invalidate(); } else { // 重新設(shè)置畫圖高度,防止高度異常 if (mPaintView.getHeight() > mPaintStartHeight + Math.abs(mScroller.getCurrY()) && !isScrllerTop && mScroller.getStartY() > 0) { lpp.height = mPaintStartHeight + Math.abs(mScroller.getCurrY()); mPaintView.setLayoutParams(lpp); } } // 防止多次調(diào)用 if (lastScrollY != mScroller.getCurrY()) { // 收縮完成 if (mScroller.getCurrY() >= 0 && !isClick) { if (null != listener) { listener.onScrollTop(mPaintScrollTextView); } } // 展開完成 if (-mScroller.getCurrY() >= getHeight() - mPaintIvHeight && !isClick) { if (null != listener) { listener.onScrollBottom(mPaintScrollTextView); } } lastScrollY = mScroller.getCurrY(); } } /** * 重置滾動(dòng) */ public void replaceScroll() { // 重置信息 scrollTo(0, 0); mScroller.setFinalY(0); lastScrollY = 0; lpp.height = mPaintStartHeight; mPaintView.setLayoutParams(lpp); if (null != listener) { listener.onScrollTop(mPaintScrollTextView); } } /** * drawable轉(zhuǎn)bitmap * * @param drawable * @return */ private Bitmap drawableToBitamp(Drawable drawable) { if (null == drawable) { return null; } if (drawable instanceof BitmapDrawable) { BitmapDrawable bd = (BitmapDrawable) drawable; return bd.getBitmap(); } int w = drawable.getIntrinsicWidth(); int h = drawable.getIntrinsicHeight(); Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); drawable.setBounds(0, 0, w, h); drawable.draw(canvas); return bitmap; } /** * 按照屏幕寬高縮放圖片 * * @param bp * @return */ private Bitmap scaleBitmal(Bitmap bp) { // 寬度比例 float scaleW = (float) screenWidth / (float) bp.getWidth(); // 高度比例 float scaleH = (float) screenHeight / (float) bp.getHeight(); // 矩陣,用于縮放圖片 Matrix matrix = new Matrix(); matrix.postScale(scaleW, scaleH); // 縮放后的圖片 Bitmap scaleBp = Bitmap.createBitmap(bp, 0, 0, bp.getWidth(), bp.getHeight(), matrix, true); return scaleBp; } /** * 設(shè)置默認(rèn)的滾軸 * * @return */ private Bitmap makeDefaultScroll() { Bitmap defaultBp = Bitmap.createBitmap(screenWidth, mPaintIvHeight, Bitmap.Config.ARGB_8888); //填充顏色 defaultBp.eraseColor(Color.parseColor("#FF0000")); return defaultBp; } /** * 將px值轉(zhuǎn)換為sp值,保證文字大小不變 */ public int px2sp(float pxValue) { final float fontScale = getContext().getResources().getDisplayMetrics().scaledDensity; return (int) (pxValue / fontScale + 0.5f); } }
activity_main:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#eeeeee" tools:context="com.example.junweiliu.scrollpaintdemo.MainActivity"> <ScrollView android:layout_width="match_parent" android:layout_height="match_parent"> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent"> <!--頭部圖片部分--> <ImageView android:id="@+id/iv_banner" android:layout_width="match_parent" android:layout_height="200dp" android:scaleType="fitXY" android:src="@mipmap/show_banner"/> <!--中間內(nèi)容部分--> <LinearLayout android:id="@+id/ll_first" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@+id/iv_banner" android:layout_marginTop="20dp" android:orientation="horizontal" android:padding="16dp"> <LinearLayout android:layout_width="0dp" android:layout_height="match_parent" android:layout_marginRight="16dp" android:layout_weight="1" android:gravity="center_horizontal" android:orientation="vertical"> <ImageView android:layout_width="80dp" android:layout_height="120dp" android:scaleType="fitXY" android:src="@mipmap/movie_playbill_a"/> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:gravity="center" android:text="藝術(shù)片" android:textColor="#666666"/> </LinearLayout> <LinearLayout android:layout_width="0dp" android:layout_height="match_parent" android:layout_marginRight="16dp" android:layout_weight="1" android:gravity="center_horizontal" android:orientation="vertical"> <ImageView android:layout_width="80dp" android:layout_height="120dp" android:scaleType="fitXY" android:src="@mipmap/movie_playbill_b"/> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:gravity="center" android:text="懷舊片" android:textColor="#666666"/> </LinearLayout> <LinearLayout android:layout_width="0dp" android:layout_height="match_parent" android:layout_marginRight="16dp" android:layout_weight="1" android:gravity="center_horizontal" android:orientation="vertical"> <ImageView android:layout_width="80dp" android:layout_height="120dp" android:scaleType="fitXY" android:src="@mipmap/movie_playbill_c"/> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:gravity="center" android:text="科幻片" android:textColor="#666666"/> </LinearLayout> <LinearLayout android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:gravity="center_horizontal" android:orientation="vertical"> <ImageView android:layout_width="80dp" android:layout_height="120dp" android:scaleType="fitXY" android:src="@mipmap/movie_playbill_d"/> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:gravity="center" android:text="動(dòng)畫片" android:textColor="#666666"/> </LinearLayout> </LinearLayout> <LinearLayout android:id="@+id/ll_sencond" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@+id/ll_first" android:layout_marginTop="20dp" android:orientation="horizontal" android:padding="16dp"> <LinearLayout android:layout_width="0dp" android:layout_height="match_parent" android:layout_marginRight="16dp" android:layout_weight="1" android:gravity="center_horizontal" android:orientation="vertical"> <ImageView android:layout_width="80dp" android:layout_height="120dp" android:scaleType="fitXY" android:src="@mipmap/movie_playbill_a"/> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:gravity="center" android:text="藝術(shù)片" android:textColor="#666666"/> </LinearLayout> <LinearLayout android:layout_width="0dp" android:layout_height="match_parent" android:layout_marginRight="16dp" android:layout_weight="1" android:gravity="center_horizontal" android:orientation="vertical"> <ImageView android:layout_width="80dp" android:layout_height="120dp" android:scaleType="fitXY" android:src="@mipmap/movie_playbill_b"/> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:gravity="center" android:text="懷舊片" android:textColor="#666666"/> </LinearLayout> <LinearLayout android:layout_width="0dp" android:layout_height="match_parent" android:layout_marginRight="16dp" android:layout_weight="1" android:gravity="center_horizontal" android:orientation="vertical"> <ImageView android:layout_width="80dp" android:layout_height="120dp" android:scaleType="fitXY" android:src="@mipmap/movie_playbill_c"/> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:gravity="center" android:text="科幻片" android:textColor="#666666"/> </LinearLayout> <LinearLayout android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:gravity="center_horizontal" android:orientation="vertical"> <ImageView android:layout_width="80dp" android:layout_height="120dp" android:scaleType="fitXY" android:src="@mipmap/movie_playbill_d"/> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:gravity="center" android:text="動(dòng)畫片" android:textColor="#666666"/> </LinearLayout> </LinearLayout> <LinearLayout android:id="@+id/ll_threeth" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@+id/ll_sencond" android:layout_marginTop="20dp" android:orientation="horizontal" android:padding="16dp"> <LinearLayout android:layout_width="0dp" android:layout_height="match_parent" android:layout_marginRight="16dp" android:layout_weight="1" android:gravity="center_horizontal" android:orientation="vertical"> <ImageView android:layout_width="80dp" android:layout_height="120dp" android:scaleType="fitXY" android:src="@mipmap/movie_playbill_a"/> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:gravity="center" android:text="藝術(shù)片" android:textColor="#666666"/> </LinearLayout> <LinearLayout android:layout_width="0dp" android:layout_height="match_parent" android:layout_marginRight="16dp" android:layout_weight="1" android:gravity="center_horizontal" android:orientation="vertical"> <ImageView android:layout_width="80dp" android:layout_height="120dp" android:scaleType="fitXY" android:src="@mipmap/movie_playbill_b"/> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:gravity="center" android:text="懷舊片" android:textColor="#666666"/> </LinearLayout> <LinearLayout android:layout_width="0dp" android:layout_height="match_parent" android:layout_marginRight="16dp" android:layout_weight="1" android:gravity="center_horizontal" android:orientation="vertical"> <ImageView android:layout_width="80dp" android:layout_height="120dp" android:scaleType="fitXY" android:src="@mipmap/movie_playbill_c"/> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:gravity="center" android:text="科幻片" android:textColor="#666666"/> </LinearLayout> <LinearLayout android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:gravity="center_horizontal" android:orientation="vertical"> <ImageView android:layout_width="80dp" android:layout_height="120dp" android:scaleType="fitXY" android:src="@mipmap/movie_playbill_d"/> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:gravity="center" android:text="動(dòng)畫片" android:textColor="#666666"/> </LinearLayout> </LinearLayout> <LinearLayout android:id="@+id/ll_fourth" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@+id/ll_threeth" android:layout_marginTop="20dp" android:orientation="horizontal" android:padding="16dp"> <LinearLayout android:layout_width="0dp" android:layout_height="match_parent" android:layout_marginRight="16dp" android:layout_weight="1" android:gravity="center_horizontal" android:orientation="vertical"> <ImageView android:layout_width="80dp" android:layout_height="120dp" android:scaleType="fitXY" android:src="@mipmap/movie_playbill_a"/> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:gravity="center" android:text="藝術(shù)片" android:textColor="#666666"/> </LinearLayout> <LinearLayout android:layout_width="0dp" android:layout_height="match_parent" android:layout_marginRight="16dp" android:layout_weight="1" android:gravity="center_horizontal" android:orientation="vertical"> <ImageView android:layout_width="80dp" android:layout_height="120dp" android:scaleType="fitXY" android:src="@mipmap/movie_playbill_b"/> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:gravity="center" android:text="懷舊片" android:textColor="#666666"/> </LinearLayout> <LinearLayout android:layout_width="0dp" android:layout_height="match_parent" android:layout_marginRight="16dp" android:layout_weight="1" android:gravity="center_horizontal" android:orientation="vertical"> <ImageView android:layout_width="80dp" android:layout_height="120dp" android:scaleType="fitXY" android:src="@mipmap/movie_playbill_c"/> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:gravity="center" android:text="科幻片" android:textColor="#666666"/> </LinearLayout> <LinearLayout android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:gravity="center_horizontal" android:orientation="vertical"> <ImageView android:layout_width="80dp" android:layout_height="120dp" android:scaleType="fitXY" android:src="@mipmap/movie_playbill_d"/> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:gravity="center" android:text="動(dòng)畫片" android:textColor="#666666"/> </LinearLayout> </LinearLayout> <!--需要顯示的圖--> <ImageView android:id="@+id/iv_paint" android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="matrix" android:src="@mipmap/show_img" android:visibility="gone"/> <!--畫軸控件--> <com.example.junweiliu.scrollpaintdemo.widget.ScrollPaintView android:id="@+id/spv_paint" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_below="@+id/iv_banner" app:paintScrollHeight="25dp" app:paintScrollSrc="@mipmap/paint_scroll_img" app:paintScrollTxt="拉我看看" app:paintScrollTxtColor="#FF000000" app:paintScrollTxtSize="16sp" > </com.example.junweiliu.scrollpaintdemo.widget.ScrollPaintView> </RelativeLayout> </ScrollView> </RelativeLayout>
attr:
<?xml version="1.0" encoding="utf-8"?> <resources> <!--畫軸的高度--> <attr name="paintScrollHeight" format="dimension"/> <!--畫軸的圖片--> <attr name="paintScrollSrc" format="reference"/> <!--畫軸文字--> <attr name="paintScrollTxt" format="string"/> <!--畫軸文字顏色--> <attr name="paintScrollTxtColor" format="color"/> <!--畫軸文字大小--> <attr name="paintScrollTxtSize" format="dimension"/> <!--滾動(dòng)速度--> <attr name="scrollSpeed" format="integer"/> <!--分割節(jié)點(diǎn)--> <attr name="scrollPartitionNode" format="integer"/> <declare-styleable name="ScrollPaintView"> <attr name="paintScrollHeight"/> <attr name="paintScrollSrc"/> <attr name="paintScrollTxt"/> <attr name="paintScrollTxtColor"/> <attr name="paintScrollTxtSize"/> <attr name="scrollSpeed"/> <attr name="scrollPartitionNode"/> </declare-styleable> </resources>
四、問題
滾動(dòng)的時(shí)間不宜設(shè)置太短,因?yàn)閯?dòng)態(tài)設(shè)置ImageView高度時(shí)可能出現(xiàn)繪制速度趕不上滾動(dòng)的速度,會(huì)出現(xiàn)錯(cuò)位,當(dāng)然時(shí)間設(shè)置太短,也看不到這種滑動(dòng)的效果了.暫時(shí)想到的做法就是這樣,應(yīng)該還會(huì)有更好的方法.
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android中ImageCropper矩形、圓形 裁剪框的實(shí)現(xiàn)方法
這篇文章主要給大家介紹了關(guān)于Android中ImageCropper矩形、圓形 裁剪框的實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧2018-07-07Android實(shí)現(xiàn)循環(huán)平移動(dòng)畫示例
這篇文章主要介紹了Android實(shí)現(xiàn)循環(huán)平移動(dòng)畫示例,本文講解實(shí)現(xiàn)用一張背景圖做循環(huán)從左往右平移動(dòng)畫,需要的朋友可以參考下2015-06-06Android編程重寫ViewGroup實(shí)現(xiàn)卡片布局的方法
這篇文章主要介紹了Android編程重寫ViewGroup實(shí)現(xiàn)卡片布局的方法,實(shí)例分析新建FlowLayout繼承ViewGroup類及設(shè)置布局文件實(shí)現(xiàn)卡片布局效果的相關(guān)技巧,需要的朋友可以參考下2016-02-02Android Studio做超好玩的拼圖游戲 附送詳細(xì)注釋源碼
這篇文章主要介紹了用Android Studio做的一個(gè)超好玩的拼圖游戲,你是0基礎(chǔ)Android小白也能包你學(xué)會(huì),另外附送超詳細(xì)注釋的源碼,建議收藏!2021-08-08強(qiáng)制Android應(yīng)用使用某個(gè)Locale的方法
這篇文章主要介紹了強(qiáng)制Android應(yīng)用使用某個(gè)Locale的方法,涉及Android基于Locale進(jìn)行語言設(shè)置的相關(guān)技巧,需要的朋友可以參考下2015-10-10Android使用fastjson庫解析json字符串實(shí)戰(zhàn)
fastjson是一個(gè)Java語言編寫的高性能功能完善的JSON庫,它采用一種“假定有序快速匹配”的算法,把JSON?Parse的性能提升到極致,是目前Java語言中最快的JSON庫,Fastjson接口簡(jiǎn)單易用,已經(jīng)被廣泛使用在緩存序列化、協(xié)議交互、Web輸出、Android客戶端等多種應(yīng)用場(chǎng)景2023-11-11Android實(shí)現(xiàn)今日頭條訂閱頻道效果
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)今日頭條訂閱頻道效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-01-01Android實(shí)現(xiàn)橫屏切換科學(xué)計(jì)算器
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)橫屏切換科學(xué)計(jì)算器,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-06-06Android自定義ViewGroup實(shí)現(xiàn)豎向引導(dǎo)界面
這篇文章主要為大家詳細(xì)介紹了Andoird自定義ViewGroup實(shí)現(xiàn)豎向引導(dǎo)界面,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-03-03