日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

漫画播放器一吐槽功能

發布時間:2024/1/1 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 漫画播放器一吐槽功能 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言

近來有些莫名的浮躁,浮躁的心態總讓我靜不下心來學習。新的一篇的文章到現在才跟大家見面,非常欣慰一直關注我的小伙伴,有你們的陪伴,一路不孤單。

Google IO大會,谷歌宣布,將Kotlin語言作為安卓開發的一級編程語言。這里推薦兩篇干貨給大家,鏈接地址如下:

kotlin中文文檔

幾款開源的Kotlin的Android項目

漫畫吐槽

先來一張圖,看看最終的實現效果:

由繁到簡,拆分吐槽功能為以下幾個自定義控件:

  • 右下角的懸浮按鈕

  • 底部帶輸入框的 Dialog

  • 吐槽控件(根據手指移動,并且可以在邊緣擠壓)

  • 吐槽展示控件

接下來,我們逐一揪一揪各個控件的具體實現方式。

懸浮按鈕(FloatButtonView)

實現功能一欄:

  • 展開與收起動畫

  • 關閉,開啟狀態

  • 實時更新吐槽數量

  • 發表按鈕接口實現

實現流程如下:

(1)、構造函數

public FloatButtonView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);//添加視圖addLayoutView();//初始化動畫initData();//添加監聽setListener();}

(2)、addLayoutView() 添加視圖

private void addLayoutView() {View view = LayoutInflater.from(getContext()).inflate(R.layout.view_float_btn, null, false);//設置 MATCH_PARENT 不然 layout_marginBottom 無效view.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));mCloseImg = (ImageView) view.findViewById(R.id.img_close);mCloseTv = (TextView) view.findViewById(R.id.tv_close);mGossipNumTv = (TextView) view.findViewById(R.id.tv_num);mCloseLayout = (RadiusLinearLayout) view.findViewById(R.id.layout_close);mPublishLayout = (RadiusLinearLayout) view.findViewById(R.id.layout_publish);mGossipLayout = (RadiusLinearLayout) view.findViewById(R.id.layout_gossip);addView(view);}

view_float_btn.xml 布局文件:

<?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"android:layout_width="match_parent"android:layout_height="match_parent"><com.github.gossipdemo.radius.RadiusLinearLayoutandroid:id="@+id/layout_close"android:layout_width="38dp"android:layout_height="38dp"android:layout_alignParentRight="true"android:layout_marginBottom="12dp"android:layout_above="@+id/layout_publish"android:layout_marginRight="15dp"android:gravity="center"android:orientation="vertical"app:rv_backgroundColor="#AF000000"app:rv_radiusHalfHeightEnable="true"><ImageViewandroid:id="@+id/img_close"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="4dp"android:src="@mipmap/ic_comp_close"/><TextViewandroid:id="@+id/tv_close"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="關閉"android:textColor="#FFF"android:textSize="8sp"/></com.github.gossipdemo.radius.RadiusLinearLayout><com.github.gossipdemo.radius.RadiusLinearLayoutandroid:layout_width="38dp"android:id="@+id/layout_publish"android:layout_height="38dp"android:layout_above="@+id/layout_gossip"android:layout_alignParentRight="true"android:layout_marginBottom="12dp"android:layout_marginRight="15dp"android:gravity="center"android:orientation="vertical"app:rv_backgroundColor="#AF000000"app:rv_radiusHalfHeightEnable="true"><ImageViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="4dp"android:src="@mipmap/ic_comp_publish"/><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="發表"android:textColor="#FFF"android:textSize="8sp"/></com.github.gossipdemo.radius.RadiusLinearLayout><com.github.gossipdemo.radius.RadiusLinearLayoutandroid:id="@+id/layout_gossip"android:layout_width="44dp"android:layout_height="44dp"android:layout_alignParentBottom="true"android:layout_alignParentRight="true"android:layout_marginBottom="12dp"android:layout_marginRight="12dp"android:gravity="center"android:orientation="vertical"app:rv_backgroundColor="#AF000000"app:rv_radiusHalfHeightEnable="true"><TextViewandroid:id="@+id/tv_num"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="0"android:textColor="#FFF"android:textSize="10sp"/><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="1dp"android:text="吐槽"android:textColor="#FFF"android:textSize="12sp"/></com.github.gossipdemo.radius.RadiusLinearLayout></RelativeLayout>

注意:添加的子視圖為 RelativeLayout 相對布局,設置 android:layout_marginBottom 會失效,針對該問題的解決方法是:給該子視圖設置布局參數的高度為填充父窗體。

view.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));

(3)、initData() 初始化展開,縮放動畫

private void initData() {mOpenAnimator = openAnimator();mCloseAnimator = closeAnimator();}

展開與縮放動畫:

/*** 展開動畫** @return*/private ValueAnimator openAnimator() {ValueAnimator animator = ValueAnimator.ofFloat(0f, 1.0f);animator.setDuration(500);animator.setInterpolator(new OvershootInterpolator());animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {setAnimatorParams(animation);}});return animator;}public ValueAnimator closeAnimator() {ValueAnimator animator = ValueAnimator.ofFloat(1.0f, 0f);animator.setDuration(200);animator.setInterpolator(new LinearInterpolator());animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {setAnimatorParams(animation);}});return animator;}/*** 設置動畫參數** @param animation*/private void setAnimatorParams(ValueAnimator animation) {float value = (float) animation.getAnimatedValue();mCloseLayout.setY(mGossipLayout.getY() - mCloseMove * value);mPublishLayout.setY(mGossipLayout.getY() - mPublishMove * value);mCloseLayout.setAlpha(value);mPublishLayout.setAlpha(value);}

實現過程比較簡單,看看效果圖:

底部帶輸入框的 Dialog

看到這里你可能會有疑問了,為啥要使用 Dialog 呢,直接在漫畫播放器底部添加輸入框不就 ok 了嗎?

最開始我也是這么干的,可是結局太悲催了。整整浪費了我一整天的時間。神坑啊 …

神坑之一:

軟鍵盤的彈起覆蓋輸入框?

這個還不簡單,設置 android:windowSoftInputMode 軟鍵盤的輸入模式,然后你會發現并沒卵用。

之后就抓狂,噴血,嘗試了各種百度,google,各大論壇搜索,各種方式嘗試 . . .,我還不相信了小樣,我還解決不了你 . . .

現實太殘酷,我失敗了。

神坑之二:

軟鍵盤的彈出和收起會影響漫畫播放器的視圖滾動?

內心已經跑過一萬匹草泥馬 …

最后我通過查看【網易動漫】的 頂部 Activity,發現人家是采用 Dialog 的方式來實現的。這使我內心平復了一丟丟,原來網易也跟我踩過相同的坑啊。

強力推薦以下兩款工具來查看和分析第三方 app 視圖層級:

1、查看頂部 Activity 路徑

2、SDK 自帶的 uiautomatorviewer.bat

下面我貼出 Dialog 的實現代碼:

public class AppDialog extends Dialog {private Context context;private View contentView;private EditText compEditText;private OnPublishListener listener;private String gossipText = "";public AppDialog(@NonNull Context context, String text) {super(context);this.context = context;this.gossipText = text;addContentView();setCanceledOnTouchOutside(true);}public AppDialog(@NonNull Context context) {this(context, "");}private void addContentView() {//布局的高度參數不要設置為 match_parent 不然 setCanceledOnTouchOutside 方法無效View view = LayoutInflater.from(context).inflate(R.layout.view_app_dialog, null);setContentView(view);//設置dialog大小this.contentView = view;this.compEditText = (EditText) view.findViewById(R.id.player_edit_view);compEditText.setOnEditorActionListener(new TextView.OnEditorActionListener() {@Overridepublic boolean onEditorAction(TextView v, int actionId, KeyEvent event) {if (listener != null) {listener.publish(v);}return false;}});if (gossipText != null) {compEditText.setText(gossipText);compEditText.setSelection(compEditText.getText().length());}Window dialogWindow = getWindow();WindowManager manager = ((Activity) context).getWindowManager();WindowManager.LayoutParams params = dialogWindow.getAttributes(); // 獲取對話框當前的參數值dialogWindow.setGravity(Gravity.BOTTOM);//對齊方式為底部對齊Display d = manager.getDefaultDisplay(); // 獲取屏幕寬、高度params.width = (int) (d.getWidth() * 1.0f); // 寬度設置為屏幕寬度,根據實際情況調整getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);//必須設置 不然輸入框會被覆蓋getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));// android:windowBackgroundgetWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);// android:backgroundDimEnabled默認是true的dialogWindow.setAttributes(params);}}

接下來是吐槽控件的實現,篇幅有點長,源碼在文章的末尾給出。

吐槽控件(GossipView)

先來看看吐槽控件的效果圖,如下:

大概實現了以下幾個效果:

  • 跟隨手指而移動

  • 邊緣擠壓

  • 多指擠壓

(1)、跟隨手指而移動

重寫 onTouchEvent 方法,返回 true 消費事件。

手指按下的同時記錄觸摸點的 X ,Y 坐標:

case MotionEvent.ACTION_DOWN:simTouchX = event.getX();simTouchY = event.getY();

手機移動時刻記錄手指的偏移量:

case MotionEvent.ACTION_MOVE:float dx = event.getX() - simTouchX;float dy = event.getY() - simTouchY;//contentLayout 表示隨著手指移動的控件contentLayout.setX(contentLayout.getX() + dx);contentLayout.setY(contentLayout.getY() + dy);simTouchX = event.getX();simTouchY = event.getY();

注意手指移動的范圍【屏幕范圍內】,超過屏幕的顯示需要邊緣處理。

(2)邊緣擠壓

邊緣擠壓主要分為:

  • 上邊緣擠壓(寬度不斷增大,高度不斷減少)

  • 下邊緣擠壓(寬度不斷增大,高度不斷減少)

  • 左邊緣擠壓(寬度不斷減少,高度不斷增大)

  • 右邊緣擠壓(寬度不斷減少,高度不斷增大)

上邊緣擠壓,分析 Y 坐標的偏移量(dy 正數),動態改變控件的布局參數(寬度=控件寬度+dy;高度=自適應父窗體),實現擠壓效果。

首先獲取到控件的布局參數

FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) itemView.getLayoutParams();

動態改變控件寬度

lp.width = itemView.getWidth()+ dy; //dy表示兩點Y坐標偏移量

計算控件寬度的最大值和最小值,如果控件的寬度小于等于最小值則最終的寬度為最小寬度,反之則為最大寬度:

//注意寬度的區間 取最大值和最小值Rect rect = new Rect();//itemView為文本控件itemView.getPaint().getTextBounds(content, 0, itemView.getText().toString().length(), rect);//最小值和最大值int minWidth = rect.height() + itemView.getPaddingTop() + itemView.getPaddingBottom();int maxWidth = rect.width() + itemView.getPaddingLeft() + itemView.getPaddingRight();//越界處理if (lp.width <= minWidth) {lp.width = minWidth;} else if (lp.width >= maxWidth) {lp.width = maxWidth;}

最后重置控件的寬度:

itemView.setLayoutParams(new FrameLayout.LayoutParams(lp.width, FrameLayout.LayoutParams.WRAP_CONTENT));

下,左,右邊緣擠壓與上邊緣擠壓類似。

(3)、多指擠壓

第二根手指按下的同時計算與第一根手指之間的距離

case MotionEvent.ACTION_POINTER_DOWN://第二根手指X坐標float multiTouchX = event.getX(1);//第二根手指Y坐標float multiTouchY = event.getY(1);//兩根手指的x距離float dx = multiTouchX - simTouchX;//兩根手指的y距離float dy = multiTouchY - simTouchY;//兩根手指的距離fingersLength = (float) Math.sqrt(dx * dx + dy * dy);

然后計算手指移動的偏移量:

float moveDx= event.getX() - event.getX(1);float moveDy= event.getY() - event.getY(1);float moveLength= (float) Math.sqrt(moveDx* moveDx+ moveDy * moveDy);//手指的偏移量float fingersDistance= moveLength- fingersLength;

最后根據偏移量調用擠壓方法。

吐槽展示控件(動態添加)

效果一欄:

實現的代碼如下:

View itemLayout = LayoutInflater.from(mGossipLayout.getContext()).inflate(R.layout.view_gossip_item, null);final RadiusTextView rtv = (RadiusTextView) itemLayout.findViewById(R.id.rvt_name);rtv.setLayoutParams(new LinearLayout.LayoutParams((int) width, ViewGroup.LayoutParams.WRAP_CONTENT));rtv.setText(text);rtv.setX(x);rtv.setY(y);mGossipLayout.addView(itemLayout);

吐槽控件細節處理的地方比較多,具體請參考 Demo

如果您有不懂的地方請給我留言。

技術交流歡迎您的加入

總結

以上是生活随笔為你收集整理的漫画播放器一吐槽功能的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。